airbnb/caravel

View on GitHub
superset-frontend/src/SqlLab/reducers/getInitialState.test.ts

Summary

Maintainability
D
2 days
Test Coverage
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import { DEFAULT_COMMON_BOOTSTRAP_DATA } from 'src/constants';
import { runningQuery, successfulQuery } from 'src/SqlLab/fixtures';
import getInitialState, { dedupeTabHistory } from './getInitialState';

const apiData = {
  common: DEFAULT_COMMON_BOOTSTRAP_DATA,
  tab_state_ids: [],
  databases: [],
  user: {
    userId: 1,
    username: 'some name',
    isActive: true,
    isAnonymous: false,
    firstName: 'first name',
    lastName: 'last name',
    permissions: {},
    roles: {},
  },
};
const apiDataWithTabState = {
  ...apiData,
  tab_state_ids: [{ id: 1, label: 'test' }],
  active_tab: {
    id: 1,
    user_id: 1,
    label: 'editor1',
    active: true,
    database_id: 1,
    sql: '',
    table_schemas: [],
    saved_query: null,
    template_params: null,
    latest_query: null,
  },
};
describe('getInitialState', () => {
  afterEach(() => {
    localStorage.clear();
  });

  it('should output the user that is passed in', () => {
    expect(getInitialState(apiData).user?.userId).toEqual(1);
  });
  it('should return undefined instead of null for templateParams', () => {
    expect(
      getInitialState(apiDataWithTabState).sqlLab?.queryEditors?.[0]
        ?.templateParams,
    ).toBeUndefined();
  });

  describe('dedupeTabHistory', () => {
    it('should dedupe the tab history', () => {
      [
        { value: [], expected: [] },
        {
          value: ['12', '3', '4', '5', '6'],
          expected: ['12', '3', '4', '5', '6'],
        },
        {
          value: [
            '1',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
          ],
          expected: ['1', '2'],
        },
        {
          value: [
            '1',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '3',
          ],
          expected: ['1', '2', '3'],
        },
        {
          value: [
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '2',
            '3',
          ],
          expected: ['2', '3'],
        },
      ].forEach(({ value, expected }) => {
        expect(dedupeTabHistory(value)).toEqual(expected);
      });
    });
  });

  describe('dedupe tables schema', () => {
    it('should dedupe the table schema', () => {
      localStorage.setItem(
        'redux',
        JSON.stringify({
          sqlLab: {
            tables: [
              { id: 1, name: 'test1' },
              { id: 6, name: 'test6' },
            ],
            queryEditors: [{ id: 1, title: 'editor1' }],
            queries: {},
            tabHistory: [],
          },
        }),
      );
      const initializedTables = getInitialState({
        ...apiData,
        active_tab: {
          id: 1,
          user_id: 1,
          label: 'editor1',
          active: true,
          database_id: 1,
          sql: '',
          table_schemas: [
            {
              id: 1,
              table: 'table1',
              tab_state_id: 1,
              description: {
                columns: [
                  { name: 'id', type: 'INT' },
                  { name: 'column2', type: 'STRING' },
                ],
              },
            },
            {
              id: 2,
              table: 'table2',
              tab_state_id: 1,
              description: {
                columns: [
                  { name: 'id', type: 'INT' },
                  { name: 'column2', type: 'STRING' },
                ],
              },
            },
          ],
          saved_query: null,
          template_params: null,
          latest_query: null,
        },
      }).sqlLab.tables;
      expect(initializedTables.map(({ id }) => id)).toEqual([1, 2, 6]);
    });

    it('should parse the float dttm value', () => {
      const startDttmInStr = '1693433503447.166992';
      const endDttmInStr = '1693433503500.23132';

      localStorage.setItem(
        'redux',
        JSON.stringify({
          sqlLab: {
            tables: [
              { id: 1, name: 'test1' },
              { id: 6, name: 'test6' },
            ],
            queryEditors: [{ id: 1, title: 'editor1' }],
            queries: {
              localStoragePersisted: {
                ...successfulQuery,
                id: 'localStoragePersisted',
                startDttm: startDttmInStr,
                endDttm: endDttmInStr,
              },
            },
            tabHistory: [],
          },
        }),
      );

      const latestQuery = {
        ...runningQuery,
        id: 'latestPersisted',
        startDttm: Number(startDttmInStr),
        endDttm: Number(endDttmInStr),
      };
      const initializedQueries = getInitialState({
        ...apiDataWithTabState,
        active_tab: {
          ...apiDataWithTabState.active_tab,
          latest_query: latestQuery,
        },
      }).sqlLab.queries;
      expect(initializedQueries.latestPersisted).toEqual(
        expect.objectContaining({
          startDttm: Number(startDttmInStr),
          endDttm: Number(endDttmInStr),
        }),
      );
      expect(initializedQueries.localStoragePersisted).toEqual(
        expect.objectContaining({
          startDttm: Number(startDttmInStr),
          endDttm: Number(endDttmInStr),
        }),
      );
    });
  });

  describe('restore unsaved changes for PERSISTENCE mode', () => {
    const lastUpdatedTime = Date.now();
    const expectedValue = 'updated editor value';
    beforeEach(() => {
      localStorage.setItem(
        'redux',
        JSON.stringify({
          sqlLab: {
            queryEditors: [
              {
                // restore cached value since updates are after server update time
                id: '1',
                name: expectedValue,
                updatedAt: lastUpdatedTime + 100,
              },
              {
                // no update required given that last updated time comes before server update time
                id: '2',
                name: expectedValue,
                updatedAt: lastUpdatedTime - 100,
              },
              {
                // no update required given that there's no updatedAt
                id: '3',
                name: expectedValue,
              },
            ],
            destroyedQueryEditors: {
              10: 12345,
            },
          },
        }),
      );
    });

    it('restore unsaved changes for PERSISTENCE mode', () => {
      const apiDataWithLocalStorage = {
        ...apiData,
        active_tab: {
          ...apiDataWithTabState.active_tab,
          id: 1,
          label: 'persisted tab',
          table_schemas: [],
          extra_json: {
            updatedAt: lastUpdatedTime,
          },
        },
        tab_state_ids: [
          { id: 1, label: '' },
          { id: 10, label: 'removed' },
        ],
      };
      expect(
        getInitialState(apiDataWithLocalStorage).sqlLab.queryEditors[0],
      ).toEqual(
        expect.objectContaining({
          id: '1',
          name: expectedValue,
        }),
      );
      expect(
        getInitialState(apiDataWithLocalStorage).sqlLab.queryEditors,
      ).not.toContainEqual(
        expect.objectContaining({
          id: '10',
        }),
      );
      expect(
        getInitialState(apiDataWithLocalStorage).sqlLab.lastUpdatedActiveTab,
      ).toEqual(apiDataWithTabState.active_tab.id.toString());
    });

    it('skip unsaved changes for expired data', () => {
      const apiDataWithLocalStorage = {
        ...apiData,
        active_tab: {
          ...apiDataWithTabState.active_tab,
          id: 2,
          label: 'persisted tab',
          table_schemas: [],
          extra_json: {
            updatedAt: lastUpdatedTime,
          },
        },
        tab_state_ids: [{ id: 2, label: '' }],
      };
      expect(
        getInitialState(apiDataWithLocalStorage).sqlLab.queryEditors[1],
      ).toEqual(
        expect.objectContaining({
          id: '2',
          name: apiDataWithLocalStorage.active_tab.label,
        }),
      );
    });

    it('skip unsaved changes for legacy cache data', () => {
      const apiDataWithLocalStorage = {
        ...apiData,
        active_tab: {
          ...apiDataWithTabState.active_tab,
          id: 3,
          label: 'persisted tab',
          table_schemas: [],
          extra_json: {
            updatedAt: lastUpdatedTime,
          },
        },
        tab_state_ids: [{ id: 3, label: '' }],
      };
      expect(
        getInitialState(apiDataWithLocalStorage).sqlLab.queryEditors[2],
      ).toEqual(
        expect.objectContaining({
          id: '3',
          name: apiDataWithLocalStorage.active_tab.label,
        }),
      );
    });
  });
});