Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add ui render for debug ui integration tests #27621

Draft
wants to merge 5 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,6 @@ html-report/

/app/images/branding
/changed-files

# UI Integration tests
test/integration/config/assets
27 changes: 16 additions & 11 deletions development/build/static.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ const { getPathInsideNodeModules } = require('./utils');

const EMPTY_JS_FILE = './development/empty.js';

module.exports = function createStaticAssetTasks({
module.exports = createStaticAssetTasks;
// Exposed for UI Integration tests preview
module.exports.getCopyTargets = getCopyTargets;
module.exports.copyGlob = copyGlob;

function createStaticAssetTasks({
livereload,
browserPlatforms,
shouldIncludeLockdown = true,
Expand Down Expand Up @@ -96,17 +101,17 @@ module.exports = function createStaticAssetTasks({
);
}
}
}

async function copyGlob(baseDir, srcGlob, dest) {
const sources = await glob(srcGlob, { onlyFiles: false });
await Promise.all(
sources.map(async (src) => {
const relativePath = path.relative(baseDir, src);
await fs.copy(src, `${dest}${relativePath}`, { overwrite: true });
}),
);
}
};
async function copyGlob(baseDir, srcGlob, dest) {
const sources = await glob(srcGlob, { onlyFiles: false });
await Promise.all(
sources.map(async (src) => {
const relativePath = path.relative(baseDir, src);
await fs.copy(src, `${dest}${relativePath}`, { overwrite: true });
}),
);
}

function getCopyTargets(shouldIncludeLockdown, shouldIncludeSnow) {
const allCopyTargets = [
Expand Down
3 changes: 3 additions & 0 deletions development/build/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ const { createTask } = require('./task');
// scss compilation and autoprefixing tasks
module.exports = createStyleTasks;

// Exposed for UI Integration tests preview
module.exports.buildScssPipeline = buildScssPipeline;

function createStyleTasks({ livereload }) {
const prod = createTask(
TASKS.STYLES_PROD,
Expand Down
68 changes: 68 additions & 0 deletions development/build/ui-integration-tests/build-preview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const del = require('del');
const { copyGlob, getCopyTargets } = require('../static');
const { buildScssPipeline } = require('../styles');

const mainDest = 'test/integration/config/assets';

/**
* Builds the styles for UI integration tests
*/
async function buildTestUIIntegrationStyles() {
await buildScssPipeline('ui/css/index.scss', `${mainDest}`);
}

/**
* Filters the copy targets to exclude unwanted files and directories
*
* @param {Array} allCopyTargets - The array of all copy targets to be filtered
* @returns {Array} Filtered copy targets
*/
function trimdownCopyTargets(allCopyTargets) {
return allCopyTargets.filter(({ src, dest }) => {
return !(
src.includes('ui/css/output') ||
dest.includes('scripts/') ||
dest.includes('snaps/') ||
src.includes('./development')
);
});
}

/**
* Copies static assets for UI integration tests
*/
async function copyTestUiIntegrationStaticAssets() {
const [, allCopyTargets] = getCopyTargets();

const uiIntegrationTestCopyTargets = trimdownCopyTargets(allCopyTargets);

for (const target of uiIntegrationTestCopyTargets) {
await copyGlob(target.src, `${target.src}`, `${mainDest}/${target.dest}`);
}
}

/**
* Runs the UI integration test build process
*/
async function run() {
try {
console.log('Build UI Integration Test: starting');
await del([`./${mainDest}/*`]);
await Promise.all([
buildTestUIIntegrationStyles(),
copyTestUiIntegrationStaticAssets(),
]);

console.log('Build UI Integration Test: completed');
} catch (error) {
console.error(error.stack || error);
process.exitCode = 1;
}
}

module.exports = {
buildTestUIIntegrationStyles,
trimdownCopyTargets,
copyTestUiIntegrationStaticAssets,
run,
};
93 changes: 93 additions & 0 deletions development/build/ui-integration-tests/build-preview.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
const del = require('del');
const { buildScssPipeline } = require('../styles');
const { copyGlob } = require('../static');
const uiIntegrationTest = require('./build-preview');

const mockTargets = [
{ src: 'ui/css/output/file.css', dest: 'css/' },
{ src: 'images/logo.png', dest: 'images/' },
{ src: 'js/main.js', dest: 'scripts/' },
{ src: 'snaps/snap1.js', dest: 'snaps/' },
{ src: './development/file.js', dest: 'dev/' },
];

// Mock the dependencies
jest.mock('../styles', () => ({
buildScssPipeline: jest.fn(),
}));

jest.mock('../static', () => ({
copyGlob: jest.fn(),
getCopyTargets: jest.fn(() => [null, mockTargets]),
}));

jest.mock('del', () => jest.fn());

describe('UI Integration Test Build', () => {
beforeEach(() => {
jest.clearAllMocks();
});

describe('buildTestUIIntegrationStyles', () => {
it('should call buildScssPipeline with correct arguments', async () => {
await uiIntegrationTest.buildTestUIIntegrationStyles();
expect(buildScssPipeline).toHaveBeenCalledWith(
'ui/css/index.scss',
'test/integration/config/assets',
);
});
});

describe('trimdownCopyTargets', () => {
it('should filter out unwanted copy targets', () => {
const result = uiIntegrationTest.trimdownCopyTargets(mockTargets);
expect(result).toHaveLength(1);
expect(result[0]).toStrictEqual({
src: 'images/logo.png',
dest: 'images/',
});
});
});

describe('copyTestUiIntegrationStaticAssets', () => {
it('should copy filtered assets', async () => {
await uiIntegrationTest.copyTestUiIntegrationStaticAssets();

expect(copyGlob).toHaveBeenCalledWith(
'images/logo.png',
'images/logo.png',
'test/integration/config/assets/images/',
);
});
});

describe('run', () => {
it('should clean the destination directory and run build tasks', async () => {
const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
await uiIntegrationTest.run();

expect(del).toHaveBeenCalledWith(['./test/integration/config/assets/*']);
expect(buildScssPipeline).toHaveBeenCalled();
expect(copyGlob).toHaveBeenCalled();
expect(consoleSpy).toHaveBeenCalledTimes(2);
const expectedCalls = [
'Build UI Integration Test: starting',
'Build UI Integration Test: completed',
];
expectedCalls.forEach((call) => {
expect(consoleSpy).toHaveBeenCalledWith(call);
});
});

it('should handle errors and set process.exitCode', async () => {
const error = new Error('Test error');
buildScssPipeline.mockRejectedValue(error);
const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();

await uiIntegrationTest.run();

expect(consoleErrorSpy).toHaveBeenCalledWith(error.stack || error);
expect(process.exitCode).toBe(1);
});
});
});
3 changes: 3 additions & 0 deletions development/build/ui-integration-tests/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const { run } = require('./build-preview');

run();
9 changes: 9 additions & 0 deletions jest.integration.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,13 @@ module.exports = {
customExportConditions: ['node', 'node-addons'],
},
workerIdleMemoryLimit: '500MB',
transform: {
// Use babel-jest to transpile tests with the next/babel preset
// https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object
'^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
'^.+\\.(css|scss|sass|less)$': 'jest-preview/transforms/css',
'^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)':
'jest-preview/transforms/file',
},
transformIgnorePatterns: ['/node_modules/'],
};
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
"test:unit:coverage": "jest --coverage",
"test:unit:webpack": "tsx --test development/webpack/test/*.test.ts",
"test:unit:webpack:coverage": "nyc --reporter=html --reporter=json --reporter=text --report-dir=./coverage/webpack tsx --test development/webpack/test/*.test.ts",
"test:integration": "jest --config jest.integration.config.js",
"test:integration:coverage": "jest --config jest.integration.config.js --coverage",
"test:integration": "node ./development/build/ui-integration-tests/index.js && jest --config jest.integration.config.js",
"test:integration:coverage": "yarn test:integration --coverage",
"test:e2e:chrome": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js",
"test:e2e:chrome:mmi": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --mmi",
"test:e2e:chrome:flask": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js --build-type flask",
Expand Down Expand Up @@ -615,6 +615,7 @@
"jest": "^29.7.0",
"jest-canvas-mock": "^2.3.1",
"jest-environment-jsdom": "patch:jest-environment-jsdom@npm%3A29.7.0#~/.yarn/patches/jest-environment-jsdom-npm-29.7.0-0b72dd0e0b.patch",
"jest-preview": "^0.3.1",
"jsdom": "^16.7.0",
"json-schema-to-ts": "^3.0.1",
"koa": "^2.7.0",
Expand Down Expand Up @@ -765,7 +766,8 @@
"core-js-pure": true,
"resolve-url-loader>es6-iterator>d>es5-ext": false,
"resolve-url-loader>es6-iterator>d>es5-ext>esniff>es5-ext": false,
"level>classic-level": false
"level>classic-level": false,
"jest-preview": false
}
},
"packageManager": "[email protected]"
Expand Down
7 changes: 7 additions & 0 deletions test/integration/config/setupAfter.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
// This file is for Jest-specific setup only and runs before our Jest tests.
import { jestPreviewConfigure } from 'jest-preview';
import '../config/assets/index.css';
import '../../helpers/setup-after-helper';

// Should be path from root of your project
jestPreviewConfigure({
publicFolder: 'test/integration/config/assets', // No need to configure if `publicFolder` is `public`
});
Loading