refactor(monorepo): change coverage of core to 100% (#17698)
This commit is contained in:
parent
89d0d38ed0
commit
07bbe8448b
|
|
@ -16,7 +16,7 @@ coverage:
|
||||||
target: auto
|
target: auto
|
||||||
threshold: 0%
|
threshold: 0%
|
||||||
core-packages-ts:
|
core-packages-ts:
|
||||||
target: 95%
|
target: 100%
|
||||||
paths:
|
paths:
|
||||||
- 'superset-frontend/packages'
|
- 'superset-frontend/packages'
|
||||||
- '!superset-frontend/packages/**/*.jsx'
|
- '!superset-frontend/packages/**/*.jsx'
|
||||||
|
|
|
||||||
|
|
@ -56,9 +56,10 @@ module.exports = {
|
||||||
coverageReporters: ['lcov', 'json-summary', 'html'],
|
coverageReporters: ['lcov', 'json-summary', 'html'],
|
||||||
transform: {
|
transform: {
|
||||||
'^.+\\.jsx?$': 'babel-jest',
|
'^.+\\.jsx?$': 'babel-jest',
|
||||||
// ts-jest can't load plugin 'babel-plugin-typescript-to-proptypes'
|
// ts-jest doesn't work with `--coverage`. @superset-ui/core should
|
||||||
'reactify\\.tsx$': 'babel-jest',
|
// 100% coverage, so we use babel-jest in packages and plugins.
|
||||||
'^.+\\.tsx?$': 'ts-jest',
|
'(plugins|packages)\\/.+\\.tsx?$': 'babel-jest',
|
||||||
|
'(((?!(plugins|packages)).)*)\\/.+\\.tsx?$': 'ts-jest',
|
||||||
},
|
},
|
||||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
|
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
|
||||||
snapshotSerializers: ['@emotion/jest/enzyme-serializer'],
|
snapshotSerializers: ['@emotion/jest/enzyme-serializer'],
|
||||||
|
|
|
||||||
|
|
@ -40,12 +40,7 @@ export default class CategoricalColorNamespace {
|
||||||
getScale(schemeId?: string) {
|
getScale(schemeId?: string) {
|
||||||
const id = schemeId ?? getCategoricalSchemeRegistry().getDefaultKey() ?? '';
|
const id = schemeId ?? getCategoricalSchemeRegistry().getDefaultKey() ?? '';
|
||||||
const scheme = getCategoricalSchemeRegistry().get(id);
|
const scheme = getCategoricalSchemeRegistry().get(id);
|
||||||
const newScale = new CategoricalColorScale(
|
return new CategoricalColorScale(scheme?.colors ?? [], this.forcedItems);
|
||||||
scheme?.colors ?? [],
|
|
||||||
this.forcedItems,
|
|
||||||
);
|
|
||||||
|
|
||||||
return newScale;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -33,13 +33,6 @@ import {
|
||||||
} from './types';
|
} from './types';
|
||||||
import { DEFAULT_FETCH_RETRY_OPTIONS, DEFAULT_BASE_URL } from './constants';
|
import { DEFAULT_FETCH_RETRY_OPTIONS, DEFAULT_BASE_URL } from './constants';
|
||||||
|
|
||||||
function redirectUnauthorized() {
|
|
||||||
// the next param will be picked by flask to redirect the user after the login
|
|
||||||
setTimeout(() => {
|
|
||||||
window.location.href = `/login?next=${window.location.href}`;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class SupersetClientClass {
|
export default class SupersetClientClass {
|
||||||
credentials: Credentials;
|
credentials: Credentials;
|
||||||
|
|
||||||
|
|
@ -159,8 +152,8 @@ export default class SupersetClientClass {
|
||||||
timeout: timeout ?? this.timeout,
|
timeout: timeout ?? this.timeout,
|
||||||
fetchRetryOptions: fetchRetryOptions ?? this.fetchRetryOptions,
|
fetchRetryOptions: fetchRetryOptions ?? this.fetchRetryOptions,
|
||||||
}).catch(res => {
|
}).catch(res => {
|
||||||
if (res && res.status === 401) {
|
if (res?.status === 401) {
|
||||||
redirectUnauthorized();
|
this.redirectUnauthorized();
|
||||||
}
|
}
|
||||||
return Promise.reject(res);
|
return Promise.reject(res);
|
||||||
});
|
});
|
||||||
|
|
@ -226,4 +219,8 @@ export default class SupersetClientClass {
|
||||||
endpoint[0] === '/' ? endpoint.slice(1) : endpoint
|
endpoint[0] === '/' ? endpoint.slice(1) : endpoint
|
||||||
}`;
|
}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
redirectUnauthorized() {
|
||||||
|
window.location.href = `/login?next=${window.location.href}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,15 +16,12 @@
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import seedrandom from 'seedrandom';
|
import _seedrandom from 'seedrandom';
|
||||||
|
|
||||||
let random = seedrandom('superset-ui');
|
|
||||||
|
|
||||||
export function seed(seed: string) {
|
export function seed(seed: string) {
|
||||||
random = seedrandom(seed);
|
return _seedrandom(seed);
|
||||||
return random;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function seedRandom() {
|
export function seedRandom() {
|
||||||
return random();
|
return _seedrandom('superset-ui')();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,7 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import fetchMock from 'fetch-mock';
|
import fetchMock from 'fetch-mock';
|
||||||
import {
|
import { SupersetClientClass, ClientConfig, CallApi } from '@superset-ui/core';
|
||||||
SupersetClientClass,
|
|
||||||
ClientConfig,
|
|
||||||
} from '@superset-ui/core/src/connection';
|
|
||||||
import { LOGIN_GLOB } from './fixtures/constants';
|
import { LOGIN_GLOB } from './fixtures/constants';
|
||||||
|
|
||||||
describe('SupersetClientClass', () => {
|
describe('SupersetClientClass', () => {
|
||||||
|
|
@ -321,7 +318,7 @@ describe('SupersetClientClass', () => {
|
||||||
await client.init();
|
await client.init();
|
||||||
await client.get({ url: mockGetUrl });
|
await client.get({ url: mockGetUrl });
|
||||||
|
|
||||||
const fetchRequest = fetchMock.calls(mockGetUrl)[0][1];
|
const fetchRequest = fetchMock.calls(mockGetUrl)[0][1] as CallApi;
|
||||||
expect(fetchRequest.mode).toBe(clientConfig.mode);
|
expect(fetchRequest.mode).toBe(clientConfig.mode);
|
||||||
expect(fetchRequest.credentials).toBe(clientConfig.credentials);
|
expect(fetchRequest.credentials).toBe(clientConfig.credentials);
|
||||||
expect(fetchRequest.headers).toEqual(
|
expect(fetchRequest.headers).toEqual(
|
||||||
|
|
@ -378,7 +375,7 @@ describe('SupersetClientClass', () => {
|
||||||
await client.init();
|
await client.init();
|
||||||
await client.get({ url: mockGetUrl, ...overrideConfig });
|
await client.get({ url: mockGetUrl, ...overrideConfig });
|
||||||
|
|
||||||
const fetchRequest = fetchMock.calls(mockGetUrl)[0][1];
|
const fetchRequest = fetchMock.calls(mockGetUrl)[0][1] as CallApi;
|
||||||
expect(fetchRequest.mode).toBe(overrideConfig.mode);
|
expect(fetchRequest.mode).toBe(overrideConfig.mode);
|
||||||
expect(fetchRequest.credentials).toBe(overrideConfig.credentials);
|
expect(fetchRequest.credentials).toBe(overrideConfig.credentials);
|
||||||
expect(fetchRequest.headers).toEqual(
|
expect(fetchRequest.headers).toEqual(
|
||||||
|
|
@ -423,7 +420,7 @@ describe('SupersetClientClass', () => {
|
||||||
await client.init();
|
await client.init();
|
||||||
await client.post({ url: mockPostUrl, ...overrideConfig });
|
await client.post({ url: mockPostUrl, ...overrideConfig });
|
||||||
|
|
||||||
const fetchRequest = fetchMock.calls(mockPostUrl)[0][1];
|
const fetchRequest = fetchMock.calls(mockPostUrl)[0][1] as CallApi;
|
||||||
|
|
||||||
expect(fetchRequest.mode).toBe(overrideConfig.mode);
|
expect(fetchRequest.mode).toBe(overrideConfig.mode);
|
||||||
expect(fetchRequest.credentials).toBe(overrideConfig.credentials);
|
expect(fetchRequest.credentials).toBe(overrideConfig.credentials);
|
||||||
|
|
@ -454,7 +451,8 @@ describe('SupersetClientClass', () => {
|
||||||
await client.init();
|
await client.init();
|
||||||
await client.post({ url: mockPostUrl, postPayload });
|
await client.post({ url: mockPostUrl, postPayload });
|
||||||
|
|
||||||
const formData = fetchMock.calls(mockPostUrl)[0][1].body as FormData;
|
const fetchRequest = fetchMock.calls(mockPostUrl)[0][1] as CallApi;
|
||||||
|
const formData = fetchRequest.body as FormData;
|
||||||
|
|
||||||
expect(fetchMock.calls(mockPostUrl)).toHaveLength(1);
|
expect(fetchMock.calls(mockPostUrl)).toHaveLength(1);
|
||||||
Object.entries(postPayload).forEach(([key, value]) => {
|
Object.entries(postPayload).forEach(([key, value]) => {
|
||||||
|
|
@ -470,7 +468,8 @@ describe('SupersetClientClass', () => {
|
||||||
await client.init();
|
await client.init();
|
||||||
await client.post({ url: mockPostUrl, postPayload, stringify: false });
|
await client.post({ url: mockPostUrl, postPayload, stringify: false });
|
||||||
|
|
||||||
const formData = fetchMock.calls(mockPostUrl)[0][1].body as FormData;
|
const fetchRequest = fetchMock.calls(mockPostUrl)[0][1] as CallApi;
|
||||||
|
const formData = fetchRequest.body as FormData;
|
||||||
|
|
||||||
expect(fetchMock.calls(mockPostUrl)).toHaveLength(1);
|
expect(fetchMock.calls(mockPostUrl)).toHaveLength(1);
|
||||||
Object.entries(postPayload).forEach(([key, value]) => {
|
Object.entries(postPayload).forEach(([key, value]) => {
|
||||||
|
|
@ -479,4 +478,36 @@ describe('SupersetClientClass', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should redirect Unauthorized', async () => {
|
||||||
|
const mockRequestUrl = 'https://host/get/url';
|
||||||
|
const { location } = window;
|
||||||
|
// @ts-ignore
|
||||||
|
delete window.location;
|
||||||
|
// @ts-ignore
|
||||||
|
window.location = { href: mockRequestUrl };
|
||||||
|
const authSpy = jest
|
||||||
|
.spyOn(SupersetClientClass.prototype, 'ensureAuth')
|
||||||
|
.mockImplementation();
|
||||||
|
const rejectValue = { status: 401 };
|
||||||
|
fetchMock.get(mockRequestUrl, () => Promise.reject(rejectValue), {
|
||||||
|
overwriteRoutes: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const client = new SupersetClientClass({});
|
||||||
|
|
||||||
|
let error;
|
||||||
|
try {
|
||||||
|
await client.request({ url: mockRequestUrl, method: 'GET' });
|
||||||
|
} catch (err) {
|
||||||
|
error = err;
|
||||||
|
} finally {
|
||||||
|
const redirectURL = window.location.href;
|
||||||
|
expect(redirectURL).toBe(`/login?next=${mockRequestUrl}`);
|
||||||
|
expect(error.status).toBe(401);
|
||||||
|
}
|
||||||
|
|
||||||
|
authSpy.mockReset();
|
||||||
|
window.location = location;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -17,16 +17,16 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { logging } from '@superset-ui/core';
|
|
||||||
import Translator from '@superset-ui/core/src/translation/Translator';
|
|
||||||
import {
|
import {
|
||||||
|
logging,
|
||||||
configure,
|
configure,
|
||||||
t,
|
t,
|
||||||
tn,
|
tn,
|
||||||
addLocaleData,
|
addLocaleData,
|
||||||
addTranslation,
|
addTranslation,
|
||||||
addTranslations,
|
addTranslations,
|
||||||
} from '@superset-ui/core/src/translation/TranslatorSingleton';
|
} from '@superset-ui/core';
|
||||||
|
import Translator from '../../src/translation/Translator';
|
||||||
import languagePackZh from './languagePacks/zh';
|
import languagePackZh from './languagePacks/zh';
|
||||||
import languagePackEn from './languagePacks/en';
|
import languagePackEn from './languagePacks/en';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,8 @@
|
||||||
|
|
||||||
/* eslint no-console: 0 */
|
/* eslint no-console: 0 */
|
||||||
import mockConsole from 'jest-mock-console';
|
import mockConsole from 'jest-mock-console';
|
||||||
import Translator from '@superset-ui/core/src/translation/Translator';
|
import { configure, resetTranslation, t, tn } from '@superset-ui/core';
|
||||||
import {
|
import Translator from '../../src/translation/Translator';
|
||||||
configure,
|
|
||||||
resetTranslation,
|
|
||||||
t,
|
|
||||||
tn,
|
|
||||||
} from '@superset-ui/core/src/translation/TranslatorSingleton';
|
|
||||||
|
|
||||||
import languagePackEn from './languagePacks/en';
|
import languagePackEn from './languagePacks/en';
|
||||||
import languagePackZh from './languagePacks/zh';
|
import languagePackZh from './languagePacks/zh';
|
||||||
|
|
@ -76,4 +71,16 @@ describe('TranslatorSingleton', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('should be reset translation setting', () => {
|
||||||
|
configure();
|
||||||
|
expect(t('second')).toEqual('second');
|
||||||
|
|
||||||
|
resetTranslation();
|
||||||
|
const restoreConsole = mockConsole();
|
||||||
|
expect(t('second')).toEqual('second');
|
||||||
|
resetTranslation();
|
||||||
|
expect(t('second')).toEqual('second');
|
||||||
|
expect(console.warn).toBeCalledTimes(2);
|
||||||
|
restoreConsole();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { configure, t, tn } from '@superset-ui/core/src/translation';
|
import { configure, t, tn } from '@superset-ui/core';
|
||||||
|
|
||||||
describe('index', () => {
|
describe('index', () => {
|
||||||
it('exports configure()', () => {
|
it('exports configure()', () => {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { LanguagePack } from '@superset-ui/core/src/translation';
|
import { LanguagePack } from '@superset-ui/core';
|
||||||
|
|
||||||
const languagePack: LanguagePack = {
|
const languagePack: LanguagePack = {
|
||||||
domain: 'superset',
|
domain: 'superset',
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { LanguagePack } from '@superset-ui/core/src/translation';
|
import { LanguagePack } from '@superset-ui/core';
|
||||||
|
|
||||||
const languagePack: LanguagePack = {
|
const languagePack: LanguagePack = {
|
||||||
domain: 'superset',
|
domain: 'superset',
|
||||||
|
|
|
||||||
|
|
@ -21,40 +21,41 @@
|
||||||
describe('logging', () => {
|
describe('logging', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.resetModules();
|
jest.resetModules();
|
||||||
// Explicit is better than implicit
|
jest.resetAllMocks();
|
||||||
console.warn = console.error = function mockedConsole(message) {
|
|
||||||
throw new Error(message);
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
it('should pipe to `console` methods', () => {
|
|
||||||
const { logging } = require('@superset-ui/core/src');
|
|
||||||
|
|
||||||
|
it('should pipe to `console` methods', () => {
|
||||||
|
const { logging } = require('@superset-ui/core');
|
||||||
|
|
||||||
|
jest.spyOn(logging, 'debug').mockImplementation();
|
||||||
|
jest.spyOn(logging, 'log').mockImplementation();
|
||||||
|
jest.spyOn(logging, 'info').mockImplementation();
|
||||||
expect(() => {
|
expect(() => {
|
||||||
logging.debug();
|
logging.debug();
|
||||||
logging.log();
|
logging.log();
|
||||||
logging.info();
|
logging.info();
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
expect(() => {
|
|
||||||
logging.warn('warn');
|
|
||||||
}).toThrow('warn');
|
|
||||||
expect(() => {
|
|
||||||
logging.error('error');
|
|
||||||
}).toThrow('error');
|
|
||||||
|
|
||||||
// to support: npx jest --silent
|
jest.spyOn(logging, 'warn').mockImplementation(() => {
|
||||||
const spy = jest.spyOn(logging, 'trace');
|
throw new Error('warn');
|
||||||
spy.mockImplementation(() => {
|
});
|
||||||
|
expect(() => logging.warn()).toThrow('warn');
|
||||||
|
|
||||||
|
jest.spyOn(logging, 'error').mockImplementation(() => {
|
||||||
|
throw new Error('error');
|
||||||
|
});
|
||||||
|
expect(() => logging.error()).toThrow('error');
|
||||||
|
|
||||||
|
jest.spyOn(logging, 'trace').mockImplementation(() => {
|
||||||
throw new Error('Trace:');
|
throw new Error('Trace:');
|
||||||
});
|
});
|
||||||
expect(() => {
|
expect(() => logging.trace()).toThrow('Trace:');
|
||||||
logging.trace();
|
|
||||||
}).toThrow('Trace:');
|
|
||||||
spy.mockRestore();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should use noop functions when console unavailable', () => {
|
it('should use noop functions when console unavailable', () => {
|
||||||
const { console } = window;
|
const { console } = window;
|
||||||
Object.assign(window, { console: undefined });
|
Object.assign(window, { console: undefined });
|
||||||
const { logging } = require('@superset-ui/core/src');
|
const { logging } = require('@superset-ui/core');
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
Object.assign(window, { console });
|
Object.assign(window, { console });
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue