diff --git a/packages/grafana-toolkit/src/cli/tasks/toolkit.build.ts b/packages/grafana-toolkit/src/cli/tasks/toolkit.build.ts index 1377a12a4f9..4104f13adc6 100644 --- a/packages/grafana-toolkit/src/cli/tasks/toolkit.build.ts +++ b/packages/grafana-toolkit/src/cli/tasks/toolkit.build.ts @@ -60,6 +60,7 @@ const copyFiles = () => { 'src/config/tsconfig.plugin.json', 'src/config/tsconfig.plugin.local.json', 'src/config/tslint.plugin.json', + 'src/config/styles.mock.js', // plugin test file 'src/plugins/e2e/commonPluginTests.ts', diff --git a/packages/grafana-toolkit/src/config/jest.plugin.config.test.ts b/packages/grafana-toolkit/src/config/jest.plugin.config.test.ts new file mode 100644 index 00000000000..794a9fcf62a --- /dev/null +++ b/packages/grafana-toolkit/src/config/jest.plugin.config.test.ts @@ -0,0 +1,34 @@ +import { jestConfig, allowedJestConfigOverrides } from './jest.plugin.config'; + +describe('Jest config', () => { + it('should throw if not supported overrides provided', () => { + const getConfig = () => jestConfig(`${__dirname}/mocks/jestSetup/unsupportedOverrides`); + + expect(getConfig).toThrow('Provided Jest config is not supported'); + }); + + it(`should allow ${allowedJestConfigOverrides} settings overrides`, () => { + const config = jestConfig(`${__dirname}/mocks/jestSetup/overrides`); + const configKeys = Object.keys(config); + + for (const whitelistedOption of allowedJestConfigOverrides) { + expect(configKeys).toContain(whitelistedOption); + } + }); + + describe('stylesheets support', () => { + it('should provide module name mapper for stylesheets by default', () => { + const config = jestConfig(`${__dirname}/mocks/jestSetup/noOverrides`); + expect(config.moduleNameMapper).toBeDefined(); + expect(Object.keys(config.moduleNameMapper)).toContain('\\.(css|sass|scss)$'); + }); + + it('should preserve mapping for stylesheets when moduleNameMapper overrides provided', () => { + const config = jestConfig(`${__dirname}/mocks/jestSetup/overrides`); + expect(config.moduleNameMapper).toBeDefined(); + expect(Object.keys(config.moduleNameMapper)).toHaveLength(2); + expect(Object.keys(config.moduleNameMapper)).toContain('\\.(css|sass|scss)$'); + expect(Object.keys(config.moduleNameMapper)).toContain('someOverride'); + }); + }); +}); diff --git a/packages/grafana-toolkit/src/config/jest.plugin.config.ts b/packages/grafana-toolkit/src/config/jest.plugin.config.ts index 6e6c64d1d15..45ba561e26a 100644 --- a/packages/grafana-toolkit/src/config/jest.plugin.config.ts +++ b/packages/grafana-toolkit/src/config/jest.plugin.config.ts @@ -1,21 +1,35 @@ import path = require('path'); import fs from 'fs'; -const whitelistedJestConfigOverrides = ['snapshotSerializers', 'moduleNameMapper']; +export const allowedJestConfigOverrides = ['snapshotSerializers', 'moduleNameMapper']; -export const jestConfig = () => { - const jestConfigOverrides = require(path.resolve(process.cwd(), 'package.json')).jest; - const blacklistedOverrides = jestConfigOverrides - ? Object.keys(jestConfigOverrides).filter(override => whitelistedJestConfigOverrides.indexOf(override) === -1) +interface EnabledJestConfigOverrides { + snapshotSerializers: string[]; + moduleNameMapper: { [key: string]: string }; +} + +export const jestConfig = (baseDir: string = process.cwd()) => { + const jestConfigOverrides = (require(path.resolve(baseDir, 'package.json')).jest || {}) as EnabledJestConfigOverrides; + + const deniedOverrides = jestConfigOverrides + ? Object.keys(jestConfigOverrides).filter(override => allowedJestConfigOverrides.indexOf(override) === -1) : []; - if (blacklistedOverrides.length > 0) { - console.error("\ngrafana-toolkit doesn't support following Jest options: ", blacklistedOverrides); - console.log('Supported Jest options are: ', JSON.stringify(whitelistedJestConfigOverrides)); + + if (deniedOverrides.length > 0) { + console.error("\ngrafana-toolkit doesn't support following Jest options: ", deniedOverrides); + console.log('Supported Jest options are: ', JSON.stringify(allowedJestConfigOverrides)); throw new Error('Provided Jest config is not supported'); } - const shimsFilePath = path.resolve(process.cwd(), 'config/jest-shim.ts'); - const setupFilePath = path.resolve(process.cwd(), 'config/jest-setup.ts'); + const shimsFilePath = path.resolve(baseDir, 'config/jest-shim.ts'); + const setupFilePath = path.resolve(baseDir, 'config/jest-setup.ts'); + + // Mock css imports for tests. Otherwise Jest will have troubles understanding SASS/CSS imports + const { moduleNameMapper, ...otherOverrides } = jestConfigOverrides; + const moduleNameMapperConfig = { + '\\.(css|sass|scss)$': `${__dirname}/styles.mock.js`, + ...moduleNameMapper, + }; const setupFile = fs.existsSync(setupFilePath) ? setupFilePath : undefined; const shimsFile = fs.existsSync(shimsFilePath) ? shimsFilePath : undefined; @@ -29,7 +43,6 @@ export const jestConfig = () => { globals: { 'ts-jest': { isolatedModules: true } }, coverageReporters: ['json-summary', 'text', 'lcov'], collectCoverageFrom: ['src/**/*.{ts,tsx}', '!**/node_modules/**', '!**/vendor/**'], - testMatch: [ '/src/**/__tests__/**/*.{js,jsx,ts,tsx}', '/src/**/*.{spec,test,jest}.{js,jsx,ts,tsx}', @@ -38,10 +51,11 @@ export const jestConfig = () => { '[/\\\\\\\\]node_modules[/\\\\\\\\].+\\\\.(js|jsx|ts|tsx)$', '^.+\\\\.module\\\\.(css|sass|scss)$', ], + moduleNameMapper: moduleNameMapperConfig, }; return { ...defaultJestConfig, - ...jestConfigOverrides, + ...otherOverrides, }; }; diff --git a/packages/grafana-toolkit/src/config/mocks/jestSetup/noOverrides/package.json b/packages/grafana-toolkit/src/config/mocks/jestSetup/noOverrides/package.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/grafana-toolkit/src/config/mocks/jestSetup/noOverrides/package.json @@ -0,0 +1 @@ +{} diff --git a/packages/grafana-toolkit/src/config/mocks/jestSetup/overrides/package.json b/packages/grafana-toolkit/src/config/mocks/jestSetup/overrides/package.json new file mode 100644 index 00000000000..3ca42a856bf --- /dev/null +++ b/packages/grafana-toolkit/src/config/mocks/jestSetup/overrides/package.json @@ -0,0 +1,8 @@ +{ + "jest": { + "moduleNameMapper": { + "someOverride": "somePath" + }, + "snapshotSerializers": "serializers" + } +} diff --git a/packages/grafana-toolkit/src/config/mocks/jestSetup/unsupportedOverrides/package.json b/packages/grafana-toolkit/src/config/mocks/jestSetup/unsupportedOverrides/package.json new file mode 100644 index 00000000000..8450f881628 --- /dev/null +++ b/packages/grafana-toolkit/src/config/mocks/jestSetup/unsupportedOverrides/package.json @@ -0,0 +1,5 @@ +{ + "jest": { + "runner": "some-runner" + } +} diff --git a/packages/grafana-toolkit/src/config/webpack/mocks/duplicates/src/styles/dark.css b/packages/grafana-toolkit/src/config/mocks/stylesheetsSupport/duplicates/src/styles/dark.css similarity index 100% rename from packages/grafana-toolkit/src/config/webpack/mocks/duplicates/src/styles/dark.css rename to packages/grafana-toolkit/src/config/mocks/stylesheetsSupport/duplicates/src/styles/dark.css diff --git a/packages/grafana-toolkit/src/config/webpack/mocks/duplicates/src/styles/dark.scss b/packages/grafana-toolkit/src/config/mocks/stylesheetsSupport/duplicates/src/styles/dark.scss similarity index 100% rename from packages/grafana-toolkit/src/config/webpack/mocks/duplicates/src/styles/dark.scss rename to packages/grafana-toolkit/src/config/mocks/stylesheetsSupport/duplicates/src/styles/dark.scss diff --git a/packages/grafana-toolkit/src/config/webpack/mocks/duplicates/src/styles/light.css b/packages/grafana-toolkit/src/config/mocks/stylesheetsSupport/duplicates/src/styles/light.css similarity index 100% rename from packages/grafana-toolkit/src/config/webpack/mocks/duplicates/src/styles/light.css rename to packages/grafana-toolkit/src/config/mocks/stylesheetsSupport/duplicates/src/styles/light.css diff --git a/packages/grafana-toolkit/src/config/webpack/mocks/missing-theme-file/src/styles/light.css b/packages/grafana-toolkit/src/config/mocks/stylesheetsSupport/missing-theme-file/src/styles/light.css similarity index 100% rename from packages/grafana-toolkit/src/config/webpack/mocks/missing-theme-file/src/styles/light.css rename to packages/grafana-toolkit/src/config/mocks/stylesheetsSupport/missing-theme-file/src/styles/light.css diff --git a/packages/grafana-toolkit/src/config/webpack/mocks/no-theme-files/src/styles/whatever.css b/packages/grafana-toolkit/src/config/mocks/stylesheetsSupport/no-theme-files/src/styles/whatever.css similarity index 100% rename from packages/grafana-toolkit/src/config/webpack/mocks/no-theme-files/src/styles/whatever.css rename to packages/grafana-toolkit/src/config/mocks/stylesheetsSupport/no-theme-files/src/styles/whatever.css diff --git a/packages/grafana-toolkit/src/config/webpack/mocks/ok/src/styles/dark.css b/packages/grafana-toolkit/src/config/mocks/stylesheetsSupport/ok/src/styles/dark.css similarity index 100% rename from packages/grafana-toolkit/src/config/webpack/mocks/ok/src/styles/dark.css rename to packages/grafana-toolkit/src/config/mocks/stylesheetsSupport/ok/src/styles/dark.css diff --git a/packages/grafana-toolkit/src/config/webpack/mocks/ok/src/styles/light.css b/packages/grafana-toolkit/src/config/mocks/stylesheetsSupport/ok/src/styles/light.css similarity index 100% rename from packages/grafana-toolkit/src/config/webpack/mocks/ok/src/styles/light.css rename to packages/grafana-toolkit/src/config/mocks/stylesheetsSupport/ok/src/styles/light.css diff --git a/packages/grafana-toolkit/src/config/styles.mock.js b/packages/grafana-toolkit/src/config/styles.mock.js new file mode 100644 index 00000000000..ebea82fe270 --- /dev/null +++ b/packages/grafana-toolkit/src/config/styles.mock.js @@ -0,0 +1,4 @@ +// Mock for handling stylesheet file imports in tests +// https://jestjs.io/docs/en/webpack.html#handling-static-assets + +module.exports = {}; diff --git a/packages/grafana-toolkit/src/config/webpack/loaders.test.ts b/packages/grafana-toolkit/src/config/webpack/loaders.test.ts index 58913d20c1a..e06d631ae60 100644 --- a/packages/grafana-toolkit/src/config/webpack/loaders.test.ts +++ b/packages/grafana-toolkit/src/config/webpack/loaders.test.ts @@ -11,12 +11,12 @@ describe('Loaders', () => { describe('getStylesheetEntries', () => { it('returns entries for dark and light theme', () => { - const result = getStylesheetEntries(`${__dirname}/mocks/ok`); + const result = getStylesheetEntries(`${__dirname}/../mocks/stylesheetsSupport/ok`); expect(Object.keys(result)).toHaveLength(2); }); it('throws on theme files duplicates', () => { const result = () => { - getStylesheetEntries(`${__dirname}/mocks/duplicates`); + getStylesheetEntries(`${__dirname}/../mocks/stylesheetsSupport/duplicates`); }; expect(result).toThrow(); }); @@ -25,19 +25,19 @@ describe('Loaders', () => { describe('hasThemeStylesheets', () => { it('throws when only one theme file is defined', () => { const result = () => { - hasThemeStylesheets(`${__dirname}/mocks/missing-theme-file`); + hasThemeStylesheets(`${__dirname}/../mocks/stylesheetsSupport/missing-theme-file`); }; expect(result).toThrow(); }); it('returns false when no theme files present', () => { - const result = hasThemeStylesheets(`${__dirname}/mocks/no-theme-files`); + const result = hasThemeStylesheets(`${__dirname}/../mocks/stylesheetsSupport/no-theme-files`); expect(result).toBeFalsy(); }); it('returns true when theme files present', () => { - const result = hasThemeStylesheets(`${__dirname}/mocks/ok`); + const result = hasThemeStylesheets(`${__dirname}/../mocks/stylesheetsSupport/ok`); expect(result).toBeTruthy(); });