From 65a08d40fbf9430c9099f24af57cc1311d59ce15 Mon Sep 17 00:00:00 2001 From: Kshitij Thareja Date: Thu, 11 Jul 2024 18:37:47 +0530 Subject: [PATCH 01/12] Introduce abstraction for component rendering functions and support for custom describe blocks --- .eslintrc.js | 5 +- jest.conf/setup.js | 4 + jest.conf/testUtils.js | 61 ++++++-- .../__tests__/KButton.spec.js | 148 +++++++----------- package.json | 4 +- 5 files changed, 118 insertions(+), 104 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index b8b42b712..4687069de 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -20,7 +20,7 @@ esLintConfig.settings['import/resolver'].nuxt = { nuxtSrcDir: 'docs', }; -// Remove linting errors for the globals defined in the jest-puppeteer package +// Remove linting errors for the globals defined in the jest-puppeteer package and testUtils esLintConfig.globals = { ...esLintConfig.globals, page: true, @@ -28,6 +28,9 @@ esLintConfig.globals = { context: true, puppeteerConfig: true, jestPuppeteer: true, + describe: "readonly", + describeUnit: "readonly", + describeVisual: "readonly" }; module.exports = esLintConfig; diff --git a/jest.conf/setup.js b/jest.conf/setup.js index d62049c5d..7eab78f48 100644 --- a/jest.conf/setup.js +++ b/jest.conf/setup.js @@ -11,6 +11,7 @@ import VueRouter from 'vue-router'; import VueIntl from 'vue-intl'; import VueCompositionAPI from '@vue/composition-api'; import KThemePlugin from '../lib/KThemePlugin'; +import { describeUnit, describeVisual } from './testUtils'; global.beforeEach(() => { return new Promise(resolve => { @@ -55,3 +56,6 @@ global.flushPromises = function flushPromises() { setImmediate(resolve); }); }; + +global.describeUnit = describeUnit; +global.describeVisual = describeVisual; diff --git a/jest.conf/testUtils.js b/jest.conf/testUtils.js index 81a23645e..7f72e4a50 100644 --- a/jest.conf/testUtils.js +++ b/jest.conf/testUtils.js @@ -1,5 +1,7 @@ import { setMedia } from 'mock-match-media'; +const percySnapshot = require('@percy/puppeteer'); + export const resizeWindow = (width, height = 768) => { window.innerWidth = width; window.innerHeight = height; @@ -10,17 +12,6 @@ export const resizeWindow = (width, height = 768) => { }); }; -export function canTakeScreenshot() { - const percyToken = process.env.PERCY_TOKEN; - const runVisualTests = process.env.TEST_TYPE === 'visual'; - if (runVisualTests && !percyToken) { - throw new Error( - 'Error: Visual tests cannot be run because PERCY_TOKEN environment variable is not set.' - ); - } - return runVisualTests && percyToken; -} - export const testAfterResize = testFunction => { let animationFrameId; const assertAfterResize = () => { @@ -29,3 +20,51 @@ export const testAfterResize = testFunction => { }; animationFrameId = requestAnimationFrame(assertAfterResize); }; + +export async function renderComponent(page, component, props) { + await page.evaluate( + ({ component, props }) => { + window.postMessage( + { + type: 'RENDER_COMPONENT', + component: component, + props: props, + }, + '*' + ); + }, + { component, props } + ); + await page.waitForSelector('#testing-playground'); + + const isComponentRendered = await page.evaluate(() => { + const testing_playground = document.querySelector('#testing-playground'); + return testing_playground && testing_playground.children.length > 0; + }); + + if (!isComponentRendered) { + // eslint-disable-next-line no-console + console.error('Component did not render in the testing playground'); + } +} + +export async function takeSnapshot(page, name) { + if (process.env.TEST_TYPE == 'visual') { + await percySnapshot(page, name); + } else { + // eslint-disable-next-line no-console + console.log(`Skipping Percy snapshot: ${name}`); + } +} + +export function describeUnit(name, fn) { + if (process.env.TEST_TYPE != 'visual') { + describe(name, fn); + } +} + +export function describeVisual(name, fn) { + if (process.env.TEST_TYPE == 'visual') { + describe(name, fn); + } +} diff --git a/lib/buttons-and-links/__tests__/KButton.spec.js b/lib/buttons-and-links/__tests__/KButton.spec.js index ca1fa251a..86b9bf7a4 100644 --- a/lib/buttons-and-links/__tests__/KButton.spec.js +++ b/lib/buttons-and-links/__tests__/KButton.spec.js @@ -1,109 +1,79 @@ import { shallowMount } from '@vue/test-utils'; -import percySnapshot from '@percy/puppeteer'; import KButton from '../KButton.vue'; -import { canTakeScreenshot } from '../../../jest.conf/testUtils'; +import { renderComponent, takeSnapshot } from '../../../jest.conf/testUtils'; describe('KButton', () => { - if (!canTakeScreenshot()) { - describe('icon related props', () => { - it('should render an icon before the text with the icon string passed to the `icon` prop', () => { - const wrapper = shallowMount(KButton, { - propsData: { - icon: 'add', - }, - }); - expect(wrapper.find('[data-test="iconBefore"]').exists()).toBe(true); + describeUnit('icon related props', () => { + it('should render an icon before the text with the icon string passed to the `icon` prop', () => { + const wrapper = shallowMount(KButton, { + propsData: { + icon: 'add', + }, }); - it('should render an icon after the text with the icon string pased to the `iconAfter` prop', () => { - const wrapper = shallowMount(KButton, { - propsData: { - iconAfter: 'video', - }, - }); - expect(wrapper.find('[data-test="iconAfter"]').exists()).toBe(true); + expect(wrapper.find('[data-test="iconBefore"]').exists()).toBe(true); + }); + it('should render an icon after the text with the icon string pased to the `iconAfter` prop', () => { + const wrapper = shallowMount(KButton, { + propsData: { + iconAfter: 'video', + }, }); - it('should render a dropdown icon when hasDropdown is true', () => { - const wrapper = shallowMount(KButton, { - propsData: { - hasDropdown: true, - }, - }); - expect(wrapper.find('[data-test="dropdownIcon"]').exists()).toBe(true); + expect(wrapper.find('[data-test="iconAfter"]').exists()).toBe(true); + }); + it('should render a dropdown icon when hasDropdown is true', () => { + const wrapper = shallowMount(KButton, { + propsData: { + hasDropdown: true, + }, }); + expect(wrapper.find('[data-test="dropdownIcon"]').exists()).toBe(true); }); + }); - describe('text prop and slots', () => { - it('should render the text prop if nothing is in the default slot', () => { - const wrapper = shallowMount(KButton, { - propsData: { - text: 'test', - }, - }); - expect(wrapper.text()).toContain('test'); + describeUnit('text prop and slots', () => { + it('should render the text prop if nothing is in the default slot', () => { + const wrapper = shallowMount(KButton, { + propsData: { + text: 'test', + }, }); + expect(wrapper.text()).toContain('test'); + }); - it('should render the slot when the slot has content', () => { - const wrapper = shallowMount(KButton, { - propsData: { - text: 'test', - }, - slots: { - default: 'slot', - }, - }); - expect(wrapper.text()).toContain('slot'); - expect(wrapper.text()).toContain('test'); + it('should render the slot when the slot has content', () => { + const wrapper = shallowMount(KButton, { + propsData: { + text: 'test', + }, + slots: { + default: 'slot', + }, }); + expect(wrapper.text()).toContain('slot'); + expect(wrapper.text()).toContain('test'); }); + }); - describe('event handling', () => { - it('should emit a click event when clicked', () => { - const wrapper = shallowMount(KButton, { - propsData: { - text: 'test', - }, - }); - wrapper.trigger('click'); - expect(wrapper.emitted().click).toBeTruthy(); + describeUnit('event handling', () => { + it('should emit a click event when clicked', () => { + const wrapper = shallowMount(KButton, { + propsData: { + text: 'test', + }, }); + wrapper.trigger('click'); + expect(wrapper.emitted().click).toBeTruthy(); }); - } else { - describe('KButton Visual Tests', () => { - beforeAll(async () => { - await page.goto('http://localhost:4000/testing-playground', { waitUntil: 'networkidle2' }); - }); + }); - async function renderComponent(component, props) { - await page.evaluate( - ({ component, props }) => { - window.postMessage( - { - type: 'RENDER_COMPONENT', - component: component, - props: props, - }, - '*' - ); - }, - { component, props } - ); - await page.waitForSelector('#testing-playground'); - - const isComponentRendered = await page.evaluate(() => { - const testing_playground = document.querySelector('#testing-playground'); - return testing_playground && testing_playground.children.length > 0; - }); - - if (!isComponentRendered) { - // eslint-disable-next-line no-console - console.error('Component did not render in the testing playground'); - } - } + describeVisual('KButton Visual Tests', () => { + beforeAll(async () => { + await page.goto('http://localhost:4000/testing-playground', { waitUntil: 'networkidle2' }); + }); - it('renders correctly with default props', async () => { - await renderComponent('KButton', { text: 'Test Button' }); - await percySnapshot(page, 'KButton - Default'); - }); + it('renders correctly with default props', async () => { + await renderComponent(page, 'KButton', { text: 'Test Button' }); + await takeSnapshot(page, 'KButton - Default'); }); - } + }); }); diff --git a/package.json b/package.json index 2fb1d6ed2..963feee0d 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,7 @@ "precompile-custom-svgs": "node utils/precompileSvgs/index.js --custom && yarn run pregenerate", "_lint-watch-fix": "yarn lint -w -m", "test:percy": "PERCY_LOGLEVEL=error npx percy exec -v -- jest --config jest.conf/visual.index.js -i ./lib/buttons-and-links/__tests__/KButton.spec.js", - "test": "yarn test:unit && yarn test:visual", - "test:unit": "jest --config=jest.conf/index.js", + "test": "jest --config=jest.conf/index.js", "test:visual": "concurrently --kill-others --success first --names \"SERVER,TEST\" -c \"bgCyan.bold,bgYellow.bold\" \"yarn dev-only > /dev/null 2>&1\" \"yarn test:percy\"", "_api-watch": "chokidar \"**/lib/**\" -c \"node utils/extractApi.js\"" }, @@ -66,7 +65,6 @@ "npm-run-all": "^4.1.5", "nuxt": "2.15.8", "prismjs": "^1.27.0", - "ps-tree": "^1.2.0", "puppeteer": "^22.11.0", "raw-loader": "0.5.1", "sass-loader": "^10.5.2", From d2ea3d195763e0e1f63f4b972dd831d914f4ae17 Mon Sep 17 00:00:00 2001 From: Kshitij Thareja Date: Sun, 14 Jul 2024 15:26:23 +0530 Subject: [PATCH 02/12] Initial workflow config --- .github/workflows/tests.yml | 59 +++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 347627c03..c844fce9d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -39,3 +39,62 @@ jobs: npm rebuild node-sass - name: Run tests run: yarn test + + visual_tests: + name: Visual tests + needs: test + if: ${{ github.event_name == 'pull_request' && needs.test.result == 'success' }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: '18.x' + - name: Cache Node.js modules + uses: actions/cache@v4 + with: + path: '**/node_modules' + key: ${{ runner.OS }}-node-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.OS }}-node- + - name: Install dependencies + run: | + yarn --frozen-lockfile + npm rebuild node-sass + - name: Run visual tests with Percy + env: + PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }} + run: yarn test:visual + - name: Upload Percy results + id: percy-results + run: | + echo "Percy build URL: $(npx percy info | grep web_url | cut -d ' ' -f 2)" + + comment: + name: Comment Percy results + needs: visual_tests + if: ${{ needs.visual_tests.result == 'success' }} + runs-on: ubuntu-latest + steps: + - name: Post results comment + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const percyUrl = `Percy build URL: ${process.env.PERCY_BUILD_URL}`; + const commentBody = ` + ### Percy Visual Test Results + ${percyUrl} + **Summary:** + - Visual diff locations + - [Percy Dashboard](${percyUrl}) + **Instructions for reviewers:** + - Access the Percy dashboard to review visual changes. + `; + github.issues.createComment({ + issue_number: context.payload.pull_request.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: commentBody + }); \ No newline at end of file From 8ce5fe850d43f241a2a77ea243a74000eede9b6d Mon Sep 17 00:00:00 2001 From: Kshitij Thareja Date: Tue, 16 Jul 2024 22:28:17 +0530 Subject: [PATCH 03/12] Fix the initial workflow for visual tests job --- .github/workflows/tests.yml | 15 +++++++++++---- jest.conf/testUtils.js | 1 - 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c844fce9d..1d6d9254f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -41,9 +41,9 @@ jobs: run: yarn test visual_tests: - name: Visual tests + name: Frontend Visual Tests needs: test - if: ${{ github.event_name == 'pull_request' && needs.test.result == 'success' }} + if: ${{ needs.test.result == 'success' }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -62,10 +62,17 @@ jobs: run: | yarn --frozen-lockfile npm rebuild node-sass - - name: Run visual tests with Percy + - name: Start server + run: | + yarn dev & + sleep 60 && + curl -sSf http://localhost:4000/testing-playground + env: + SHELL: /bin/bash + - name: Run visual tests + run: yarn test:percy env: PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }} - run: yarn test:visual - name: Upload Percy results id: percy-results run: | diff --git a/jest.conf/testUtils.js b/jest.conf/testUtils.js index 7f72e4a50..8285bf91b 100644 --- a/jest.conf/testUtils.js +++ b/jest.conf/testUtils.js @@ -1,5 +1,4 @@ import { setMedia } from 'mock-match-media'; - const percySnapshot = require('@percy/puppeteer'); export const resizeWindow = (width, height = 768) => { From 2eaabdb974c204bef9108bdf20391ac77f9566f8 Mon Sep 17 00:00:00 2001 From: Kshitij Thareja Date: Wed, 17 Jul 2024 14:11:03 +0530 Subject: [PATCH 04/12] Add automatic comments job for visual testing workflow --- .github/workflows/tests.yml | 61 ++++++++++++++++++++++--------------- package.json | 2 +- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1d6d9254f..8991d68bc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -43,8 +43,10 @@ jobs: visual_tests: name: Frontend Visual Tests needs: test - if: ${{ needs.test.result == 'success' }} + if: ${{ github.event_name == 'pull_request' && needs.test.result == 'success' }} runs-on: ubuntu-latest + outputs: + percy_url: ${{ steps.extract-url.outputs.percy_url }} steps: - uses: actions/checkout@v4 - name: Use Node.js @@ -70,13 +72,22 @@ jobs: env: SHELL: /bin/bash - name: Run visual tests - run: yarn test:percy + id: run-visual-tests + run: | + yarn test:percy 2>&1 | tee test-output.log env: PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }} - - name: Upload Percy results - id: percy-results + + - name: Extract Percy build URL + id: extract-url run: | - echo "Percy build URL: $(npx percy info | grep web_url | cut -d ' ' -f 2)" + url=$(grep -o 'https://percy.io/[a-zA-Z0-9/_-]*' test-output.log | tail -1) + echo "PERCY_BUILD_URL=$url" >> $GITHUB_ENV + echo "percy_url=$url" >> $GITHUB_OUTPUT + echo "Percy build URL: $url" + - name: Check extracted Percy URL + run: | + echo "Extracted Percy URL: ${{ steps.extract-url.outputs.percy_url }}" comment: name: Comment Percy results @@ -84,24 +95,26 @@ jobs: if: ${{ needs.visual_tests.result == 'success' }} runs-on: ubuntu-latest steps: + - name: Check Percy URL + run: | + echo "Percy URL: ${{ needs.visual_tests.outputs.percy_url }}" - name: Post results comment - uses: actions/github-script@v6 + uses: thollander/actions-comment-pull-request@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PERCY_BUILD_URL: ${{ env.PERCY_BUILD_URL }} with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const percyUrl = `Percy build URL: ${process.env.PERCY_BUILD_URL}`; - const commentBody = ` - ### Percy Visual Test Results - ${percyUrl} - **Summary:** - - Visual diff locations - - [Percy Dashboard](${percyUrl}) - **Instructions for reviewers:** - - Access the Percy dashboard to review visual changes. - `; - github.issues.createComment({ - issue_number: context.payload.pull_request.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: commentBody - }); \ No newline at end of file + message: | + ### Percy Visual Test Results + **Percy Dashboard:** [View Detailed Report](${{ needs.visual_tests.outputs.percy_url }}) + + **Environment:** + - **Node.js Version:** 18.x + - **OS:** Ubuntu-latest + + **Instructions for Reviewers:** + - Click on the [Percy Dashboard](${{ needs.visual_tests.outputs.percy_url }}) link to view detailed visual diffs. + - Review the visual changes highlighted in the report. + - Approve or request changes based on the visual differences. + comment_tag: execution + mode: recreate \ No newline at end of file diff --git a/package.json b/package.json index 963feee0d..a711214e3 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "precompile-svgs": "node utils/precompileSvgs/index.js && yarn run pregenerate", "precompile-custom-svgs": "node utils/precompileSvgs/index.js --custom && yarn run pregenerate", "_lint-watch-fix": "yarn lint -w -m", - "test:percy": "PERCY_LOGLEVEL=error npx percy exec -v -- jest --config jest.conf/visual.index.js -i ./lib/buttons-and-links/__tests__/KButton.spec.js", + "test:percy": "PERCY_LOGLEVEL=info npx percy exec -v -- jest --config jest.conf/visual.index.js -i ./lib/buttons-and-links/__tests__/KButton.spec.js", "test": "jest --config=jest.conf/index.js", "test:visual": "concurrently --kill-others --success first --names \"SERVER,TEST\" -c \"bgCyan.bold,bgYellow.bold\" \"yarn dev-only > /dev/null 2>&1\" \"yarn test:percy\"", "_api-watch": "chokidar \"**/lib/**\" -c \"node utils/extractApi.js\"" From 310f75b40df71b269083a97ba26d5f2156f11f01 Mon Sep 17 00:00:00 2001 From: Kshitij Thareja Date: Wed, 17 Jul 2024 14:12:08 +0530 Subject: [PATCH 05/12] Fix lint errors --- jest.conf/testUtils.js | 1 + 1 file changed, 1 insertion(+) diff --git a/jest.conf/testUtils.js b/jest.conf/testUtils.js index 8285bf91b..7f72e4a50 100644 --- a/jest.conf/testUtils.js +++ b/jest.conf/testUtils.js @@ -1,4 +1,5 @@ import { setMedia } from 'mock-match-media'; + const percySnapshot = require('@percy/puppeteer'); export const resizeWindow = (width, height = 768) => { From f6c66f3c509fee3855971cb5cbf0849c48bb7c3f Mon Sep 17 00:00:00 2001 From: Kshitij Thareja Date: Wed, 17 Jul 2024 22:37:20 +0530 Subject: [PATCH 06/12] Abstraction for page navigation --- jest.conf/testUtils.js | 8 +++++++- lib/buttons-and-links/__tests__/KButton.spec.js | 4 ---- package.json | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/jest.conf/testUtils.js b/jest.conf/testUtils.js index 7f72e4a50..473bcc70e 100644 --- a/jest.conf/testUtils.js +++ b/jest.conf/testUtils.js @@ -1,6 +1,7 @@ import { setMedia } from 'mock-match-media'; const percySnapshot = require('@percy/puppeteer'); +const TESTING_PLAYGROUND_URL = 'http://localhost:4000/testing-playground'; export const resizeWindow = (width, height = 768) => { window.innerWidth = width; @@ -65,6 +66,11 @@ export function describeUnit(name, fn) { export function describeVisual(name, fn) { if (process.env.TEST_TYPE == 'visual') { - describe(name, fn); + describe(name, () => { + beforeAll(async () => { + await page.goto(TESTING_PLAYGROUND_URL, { waitUntil: 'networkidle2' }); + }); + fn(); + }); } } diff --git a/lib/buttons-and-links/__tests__/KButton.spec.js b/lib/buttons-and-links/__tests__/KButton.spec.js index 86b9bf7a4..e5eb1ccfe 100644 --- a/lib/buttons-and-links/__tests__/KButton.spec.js +++ b/lib/buttons-and-links/__tests__/KButton.spec.js @@ -67,10 +67,6 @@ describe('KButton', () => { }); describeVisual('KButton Visual Tests', () => { - beforeAll(async () => { - await page.goto('http://localhost:4000/testing-playground', { waitUntil: 'networkidle2' }); - }); - it('renders correctly with default props', async () => { await renderComponent(page, 'KButton', { text: 'Test Button' }); await takeSnapshot(page, 'KButton - Default'); diff --git a/package.json b/package.json index 963feee0d..a711214e3 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "precompile-svgs": "node utils/precompileSvgs/index.js && yarn run pregenerate", "precompile-custom-svgs": "node utils/precompileSvgs/index.js --custom && yarn run pregenerate", "_lint-watch-fix": "yarn lint -w -m", - "test:percy": "PERCY_LOGLEVEL=error npx percy exec -v -- jest --config jest.conf/visual.index.js -i ./lib/buttons-and-links/__tests__/KButton.spec.js", + "test:percy": "PERCY_LOGLEVEL=info npx percy exec -v -- jest --config jest.conf/visual.index.js -i ./lib/buttons-and-links/__tests__/KButton.spec.js", "test": "jest --config=jest.conf/index.js", "test:visual": "concurrently --kill-others --success first --names \"SERVER,TEST\" -c \"bgCyan.bold,bgYellow.bold\" \"yarn dev-only > /dev/null 2>&1\" \"yarn test:percy\"", "_api-watch": "chokidar \"**/lib/**\" -c \"node utils/extractApi.js\"" From 1eba82f85318b25643c1696d73e5b5b3ccf86373 Mon Sep 17 00:00:00 2001 From: Kshitij Thareja Date: Wed, 17 Jul 2024 22:51:57 +0530 Subject: [PATCH 07/12] Fix lint errors --- .eslintrc.js | 3 ++- jest.conf/testUtils.js | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.eslintrc.js b/.eslintrc.js index 4687069de..a954d91ee 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -30,7 +30,8 @@ esLintConfig.globals = { jestPuppeteer: true, describe: "readonly", describeUnit: "readonly", - describeVisual: "readonly" + describeVisual: "readonly", + beforeAll: "readonly" }; module.exports = esLintConfig; diff --git a/jest.conf/testUtils.js b/jest.conf/testUtils.js index 473bcc70e..a210aea10 100644 --- a/jest.conf/testUtils.js +++ b/jest.conf/testUtils.js @@ -1,6 +1,7 @@ import { setMedia } from 'mock-match-media'; const percySnapshot = require('@percy/puppeteer'); + const TESTING_PLAYGROUND_URL = 'http://localhost:4000/testing-playground'; export const resizeWindow = (width, height = 768) => { From f4373a032375775318108dd155f731ed69d34a89 Mon Sep 17 00:00:00 2001 From: Kshitij Thareja Date: Thu, 18 Jul 2024 00:58:00 +0530 Subject: [PATCH 08/12] Introduce visual testing to the existing Javascript tests workflow --- .github/workflows/tests.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8991d68bc..1b13b21a7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -77,17 +77,11 @@ jobs: yarn test:percy 2>&1 | tee test-output.log env: PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }} - - name: Extract Percy build URL id: extract-url run: | url=$(grep -o 'https://percy.io/[a-zA-Z0-9/_-]*' test-output.log | tail -1) - echo "PERCY_BUILD_URL=$url" >> $GITHUB_ENV echo "percy_url=$url" >> $GITHUB_OUTPUT - echo "Percy build URL: $url" - - name: Check extracted Percy URL - run: | - echo "Extracted Percy URL: ${{ steps.extract-url.outputs.percy_url }}" comment: name: Comment Percy results @@ -95,14 +89,10 @@ jobs: if: ${{ needs.visual_tests.result == 'success' }} runs-on: ubuntu-latest steps: - - name: Check Percy URL - run: | - echo "Percy URL: ${{ needs.visual_tests.outputs.percy_url }}" - name: Post results comment uses: thollander/actions-comment-pull-request@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PERCY_BUILD_URL: ${{ env.PERCY_BUILD_URL }} with: message: | ### Percy Visual Test Results From c0e977f4b2f2163d7d1b3650f5832c228a8e5a3d Mon Sep 17 00:00:00 2001 From: Kshitij Thareja Date: Sat, 20 Jul 2024 17:49:51 +0530 Subject: [PATCH 09/12] Replace usage of custom describe blocks with test regex patterns --- .eslintrc.js | 4 -- jest.conf/setup.js | 4 -- jest.conf/testUtils.js | 57 ------------------- jest.conf/visual.setup.js | 5 ++ jest.conf/visual.testUtils.js | 43 ++++++++++++++ .../__tests__/KButton.spec.js | 14 ++--- package.json | 4 +- yarn.lock | 55 +----------------- 8 files changed, 59 insertions(+), 127 deletions(-) create mode 100644 jest.conf/visual.testUtils.js diff --git a/.eslintrc.js b/.eslintrc.js index a954d91ee..6f77eee99 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -28,10 +28,6 @@ esLintConfig.globals = { context: true, puppeteerConfig: true, jestPuppeteer: true, - describe: "readonly", - describeUnit: "readonly", - describeVisual: "readonly", - beforeAll: "readonly" }; module.exports = esLintConfig; diff --git a/jest.conf/setup.js b/jest.conf/setup.js index 7eab78f48..d62049c5d 100644 --- a/jest.conf/setup.js +++ b/jest.conf/setup.js @@ -11,7 +11,6 @@ import VueRouter from 'vue-router'; import VueIntl from 'vue-intl'; import VueCompositionAPI from '@vue/composition-api'; import KThemePlugin from '../lib/KThemePlugin'; -import { describeUnit, describeVisual } from './testUtils'; global.beforeEach(() => { return new Promise(resolve => { @@ -56,6 +55,3 @@ global.flushPromises = function flushPromises() { setImmediate(resolve); }); }; - -global.describeUnit = describeUnit; -global.describeVisual = describeVisual; diff --git a/jest.conf/testUtils.js b/jest.conf/testUtils.js index a210aea10..0023aaf00 100644 --- a/jest.conf/testUtils.js +++ b/jest.conf/testUtils.js @@ -1,9 +1,5 @@ import { setMedia } from 'mock-match-media'; -const percySnapshot = require('@percy/puppeteer'); - -const TESTING_PLAYGROUND_URL = 'http://localhost:4000/testing-playground'; - export const resizeWindow = (width, height = 768) => { window.innerWidth = width; window.innerHeight = height; @@ -22,56 +18,3 @@ export const testAfterResize = testFunction => { }; animationFrameId = requestAnimationFrame(assertAfterResize); }; - -export async function renderComponent(page, component, props) { - await page.evaluate( - ({ component, props }) => { - window.postMessage( - { - type: 'RENDER_COMPONENT', - component: component, - props: props, - }, - '*' - ); - }, - { component, props } - ); - await page.waitForSelector('#testing-playground'); - - const isComponentRendered = await page.evaluate(() => { - const testing_playground = document.querySelector('#testing-playground'); - return testing_playground && testing_playground.children.length > 0; - }); - - if (!isComponentRendered) { - // eslint-disable-next-line no-console - console.error('Component did not render in the testing playground'); - } -} - -export async function takeSnapshot(page, name) { - if (process.env.TEST_TYPE == 'visual') { - await percySnapshot(page, name); - } else { - // eslint-disable-next-line no-console - console.log(`Skipping Percy snapshot: ${name}`); - } -} - -export function describeUnit(name, fn) { - if (process.env.TEST_TYPE != 'visual') { - describe(name, fn); - } -} - -export function describeVisual(name, fn) { - if (process.env.TEST_TYPE == 'visual') { - describe(name, () => { - beforeAll(async () => { - await page.goto(TESTING_PLAYGROUND_URL, { waitUntil: 'networkidle2' }); - }); - fn(); - }); - } -} diff --git a/jest.conf/visual.setup.js b/jest.conf/visual.setup.js index 0e983657c..6b80ecc30 100644 --- a/jest.conf/visual.setup.js +++ b/jest.conf/visual.setup.js @@ -4,4 +4,9 @@ import { percySnapshot } from '@percy/puppeteer'; // Set the test type to visual process.env.TEST_TYPE = 'visual'; +const TESTING_PLAYGROUND_URL = 'http://localhost:4000/testing-playground'; global.percySnapshot = percySnapshot; + +global.beforeAll(async () => { + await page.goto(TESTING_PLAYGROUND_URL, { waitUntil: 'networkidle2' }); +}); diff --git a/jest.conf/visual.testUtils.js b/jest.conf/visual.testUtils.js new file mode 100644 index 000000000..18fcda38e --- /dev/null +++ b/jest.conf/visual.testUtils.js @@ -0,0 +1,43 @@ +import percySnapshot from '@percy/puppeteer'; + +export async function renderComponent(component, props) { + const initialState = await page.evaluate(() => { + const testing_playground = document.querySelector('#testing-playground'); + return testing_playground ? testing_playground.innerHTML : ''; + }); + await page.evaluate( + ({ component, props }) => { + window.postMessage( + { + type: 'RENDER_COMPONENT', + component: component, + props: props, + }, + '*' + ); + }, + { component, props } + ); + await page.waitForSelector('#testing-playground'); + + await page.waitForFunction( + initialState => { + const testing_playground = document.querySelector('#testing-playground'); + return testing_playground && testing_playground.innerHTML !== initialState; + }, + {}, + initialState + ); + const isComponentRendered = await page.evaluate(initialState => { + const testing_playground = document.querySelector('#testing-playground'); + return testing_playground && testing_playground.innerHTML !== initialState; + }, initialState); + + global.expect(isComponentRendered).toBe(true); +} + +export async function takeSnapshot(name) { + if (process.env.TEST_TYPE == 'visual') { + await percySnapshot(page, name); + } +} diff --git a/lib/buttons-and-links/__tests__/KButton.spec.js b/lib/buttons-and-links/__tests__/KButton.spec.js index e5eb1ccfe..b46cb8808 100644 --- a/lib/buttons-and-links/__tests__/KButton.spec.js +++ b/lib/buttons-and-links/__tests__/KButton.spec.js @@ -1,9 +1,9 @@ import { shallowMount } from '@vue/test-utils'; import KButton from '../KButton.vue'; -import { renderComponent, takeSnapshot } from '../../../jest.conf/testUtils'; +import { renderComponent, takeSnapshot } from '../../../jest.conf/visual.testUtils'; describe('KButton', () => { - describeUnit('icon related props', () => { + describe('icon related props', () => { it('should render an icon before the text with the icon string passed to the `icon` prop', () => { const wrapper = shallowMount(KButton, { propsData: { @@ -30,7 +30,7 @@ describe('KButton', () => { }); }); - describeUnit('text prop and slots', () => { + describe('text prop and slots', () => { it('should render the text prop if nothing is in the default slot', () => { const wrapper = shallowMount(KButton, { propsData: { @@ -54,7 +54,7 @@ describe('KButton', () => { }); }); - describeUnit('event handling', () => { + describe('event handling', () => { it('should emit a click event when clicked', () => { const wrapper = shallowMount(KButton, { propsData: { @@ -66,10 +66,10 @@ describe('KButton', () => { }); }); - describeVisual('KButton Visual Tests', () => { + describe('[Visual] KButton Visual Tests', () => { it('renders correctly with default props', async () => { - await renderComponent(page, 'KButton', { text: 'Test Button' }); - await takeSnapshot(page, 'KButton - Default'); + await renderComponent('KButton', { text: 'Test Button' }); + await takeSnapshot('KButton - Default'); }); }); }); diff --git a/package.json b/package.json index a711214e3..3f25d10c0 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ "precompile-svgs": "node utils/precompileSvgs/index.js && yarn run pregenerate", "precompile-custom-svgs": "node utils/precompileSvgs/index.js --custom && yarn run pregenerate", "_lint-watch-fix": "yarn lint -w -m", - "test:percy": "PERCY_LOGLEVEL=info npx percy exec -v -- jest --config jest.conf/visual.index.js -i ./lib/buttons-and-links/__tests__/KButton.spec.js", - "test": "jest --config=jest.conf/index.js", + "test:percy": "PERCY_LOGLEVEL=info npx percy exec -v -- jest --config jest.conf/visual.index.js -i ./lib/buttons-and-links/__tests__/KButton.spec.js -t '\\[Visual\\]'", + "test": "jest --config=jest.conf/index.js -t '^(?!.*\\[Visual\\])'", "test:visual": "concurrently --kill-others --success first --names \"SERVER,TEST\" -c \"bgCyan.bold,bgYellow.bold\" \"yarn dev-only > /dev/null 2>&1\" \"yarn test:percy\"", "_api-watch": "chokidar \"**/lib/**\" -c \"node utils/extractApi.js\"" }, diff --git a/yarn.lock b/yarn.lock index 10c582cd3..ba5628288 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5778,7 +5778,7 @@ dotenv@^9.0.2: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-9.0.2.tgz#dacc20160935a37dea6364aa1bef819fb9b6ab05" integrity sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg== -duplexer@^0.1.2, duplexer@~0.1.1: +duplexer@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== @@ -6338,19 +6338,6 @@ etag@^1.8.1, etag@~1.8.1: resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== -event-stream@=3.3.4: - version "3.3.4" - resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" - integrity sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g== - dependencies: - duplexer "~0.1.1" - from "~0" - map-stream "~0.1.0" - pause-stream "0.0.11" - split "0.3" - stream-combiner "~0.0.4" - through "~2.3.1" - eventemitter3@^4.0.0: version "4.0.7" resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" @@ -6890,11 +6877,6 @@ from2@^2.1.0: inherits "^2.0.1" readable-stream "^2.0.0" -from@~0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" - integrity sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g== - fs-exists-sync@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" @@ -9604,11 +9586,6 @@ map-obj@^4.0.0: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== -map-stream@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" - integrity sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g== - map-values@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/map-values/-/map-values-1.0.1.tgz" @@ -10881,13 +10858,6 @@ path-type@^4.0.0: resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -pause-stream@0.0.11: - version "0.0.11" - resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" - integrity sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A== - dependencies: - through "~2.3" - pbkdf2@^3.0.3, pbkdf2@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz" @@ -12083,13 +12053,6 @@ prr@~1.0.1: resolved "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz" integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= -ps-tree@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.2.0.tgz#5e7425b89508736cdd4f2224d028f7bb3f722ebd" - integrity sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA== - dependencies: - event-stream "=3.3.4" - pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz" @@ -13508,13 +13471,6 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" -split@0.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" - integrity sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA== - dependencies: - through "2" - sprintf-js@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" @@ -13620,13 +13576,6 @@ stream-browserify@^2.0.1: inherits "~2.0.1" readable-stream "^2.0.2" -stream-combiner@~0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" - integrity sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw== - dependencies: - duplexer "~0.1.1" - stream-each@^1.1.0: version "1.2.3" resolved "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz" @@ -14254,7 +14203,7 @@ through2@^2.0.0: readable-stream "~2.3.6" xtend "~4.0.1" -through@2, through@^2.3.6, through@^2.3.8, through@~2.3, through@~2.3.1: +through@^2.3.6, through@^2.3.8: version "2.3.8" resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= From 61c98f97fd2811dde712ae2b41f75b7bd587d92a Mon Sep 17 00:00:00 2001 From: Kshitij Thareja Date: Sat, 20 Jul 2024 17:56:53 +0530 Subject: [PATCH 10/12] Remove unintentional changes --- .github/workflows/tests.yml | 71 +------------------------------------ 1 file changed, 1 insertion(+), 70 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1b13b21a7..4b1de12be 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,73 +38,4 @@ jobs: yarn --frozen-lockfile npm rebuild node-sass - name: Run tests - run: yarn test - - visual_tests: - name: Frontend Visual Tests - needs: test - if: ${{ github.event_name == 'pull_request' && needs.test.result == 'success' }} - runs-on: ubuntu-latest - outputs: - percy_url: ${{ steps.extract-url.outputs.percy_url }} - steps: - - uses: actions/checkout@v4 - - name: Use Node.js - uses: actions/setup-node@v4 - with: - node-version: '18.x' - - name: Cache Node.js modules - uses: actions/cache@v4 - with: - path: '**/node_modules' - key: ${{ runner.OS }}-node-${{ hashFiles('**/yarn.lock') }} - restore-keys: | - ${{ runner.OS }}-node- - - name: Install dependencies - run: | - yarn --frozen-lockfile - npm rebuild node-sass - - name: Start server - run: | - yarn dev & - sleep 60 && - curl -sSf http://localhost:4000/testing-playground - env: - SHELL: /bin/bash - - name: Run visual tests - id: run-visual-tests - run: | - yarn test:percy 2>&1 | tee test-output.log - env: - PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }} - - name: Extract Percy build URL - id: extract-url - run: | - url=$(grep -o 'https://percy.io/[a-zA-Z0-9/_-]*' test-output.log | tail -1) - echo "percy_url=$url" >> $GITHUB_OUTPUT - - comment: - name: Comment Percy results - needs: visual_tests - if: ${{ needs.visual_tests.result == 'success' }} - runs-on: ubuntu-latest - steps: - - name: Post results comment - uses: thollander/actions-comment-pull-request@v2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - message: | - ### Percy Visual Test Results - **Percy Dashboard:** [View Detailed Report](${{ needs.visual_tests.outputs.percy_url }}) - - **Environment:** - - **Node.js Version:** 18.x - - **OS:** Ubuntu-latest - - **Instructions for Reviewers:** - - Click on the [Percy Dashboard](${{ needs.visual_tests.outputs.percy_url }}) link to view detailed visual diffs. - - Review the visual changes highlighted in the report. - - Approve or request changes based on the visual differences. - comment_tag: execution - mode: recreate \ No newline at end of file + run: yarn test \ No newline at end of file From fde97dbcca9087bece9cc2596df93018220fc287 Mon Sep 17 00:00:00 2001 From: Kshitij Thareja Date: Tue, 23 Jul 2024 23:44:54 +0530 Subject: [PATCH 11/12] Add comments for rendering function and make variable names clear --- jest.conf/visual.testUtils.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/jest.conf/visual.testUtils.js b/jest.conf/visual.testUtils.js index 18fcda38e..d7b87db37 100644 --- a/jest.conf/visual.testUtils.js +++ b/jest.conf/visual.testUtils.js @@ -1,10 +1,11 @@ import percySnapshot from '@percy/puppeteer'; export async function renderComponent(component, props) { - const initialState = await page.evaluate(() => { + const beforeRenderState = await page.evaluate(() => { const testing_playground = document.querySelector('#testing-playground'); return testing_playground ? testing_playground.innerHTML : ''; }); + await page.evaluate( ({ component, props }) => { window.postMessage( @@ -20,18 +21,21 @@ export async function renderComponent(component, props) { ); await page.waitForSelector('#testing-playground'); + // Wait until the innerHTML of the testing playground changes, indicating that the component has been rendered. await page.waitForFunction( initialState => { const testing_playground = document.querySelector('#testing-playground'); return testing_playground && testing_playground.innerHTML !== initialState; }, {}, - initialState + beforeRenderState ); + + // Check if the component has been rendered by comparing the initial state with the current state. const isComponentRendered = await page.evaluate(initialState => { const testing_playground = document.querySelector('#testing-playground'); return testing_playground && testing_playground.innerHTML !== initialState; - }, initialState); + }, beforeRenderState); global.expect(isComponentRendered).toBe(true); } From 93f2b7c69f66bf6c218ade5b1909545d649313d1 Mon Sep 17 00:00:00 2001 From: Kshitij Thareja Date: Fri, 26 Jul 2024 17:53:47 +0530 Subject: [PATCH 12/12] Add special test blocks for visual tests to append Visual tag automatically --- jest.conf/index.js | 1 + jest.conf/setup.js | 9 +++++++++ jest.conf/visual.index.js | 1 + lib/buttons-and-links/__tests__/KButton.spec.js | 2 +- package.json | 4 ++-- 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/jest.conf/index.js b/jest.conf/index.js index d534833b3..61b06d735 100644 --- a/jest.conf/index.js +++ b/jest.conf/index.js @@ -10,6 +10,7 @@ const moduleNameMapper = { module.exports = { rootDir: path.resolve(__dirname, '..'), moduleFileExtensions: ['js', 'json', 'vue'], + testNamePattern: '^(?!.*\\[Visual\\])', moduleNameMapper, testEnvironment: 'jsdom', testEnvironmentOptions: { diff --git a/jest.conf/setup.js b/jest.conf/setup.js index d62049c5d..f600b044d 100644 --- a/jest.conf/setup.js +++ b/jest.conf/setup.js @@ -28,6 +28,15 @@ global.afterEach(() => { }); }); +// Configure special test blocks for visual tests +global.describe.visual = (name, fn) => { + global.describe(`[Visual] ${name}`, fn); +}; + +global.it.visual = (name, fn) => { + global.it(`[Visual] ${name}`, fn); +}; + // Register Vue plugins and components Vue.use(VueRouter); Vue.use(VueCompositionAPI); diff --git a/jest.conf/visual.index.js b/jest.conf/visual.index.js index f041c1326..c6b5dba88 100644 --- a/jest.conf/visual.index.js +++ b/jest.conf/visual.index.js @@ -94,6 +94,7 @@ module.exports = async () => { preset: 'jest-puppeteer', testTimeout: 50000, moduleFileExtensions: ['js', 'json', 'vue'], + testNamePattern: '\\[Visual\\]', moduleNameMapper: { '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|css)$': path.resolve( __dirname, diff --git a/lib/buttons-and-links/__tests__/KButton.spec.js b/lib/buttons-and-links/__tests__/KButton.spec.js index b46cb8808..cd359f727 100644 --- a/lib/buttons-and-links/__tests__/KButton.spec.js +++ b/lib/buttons-and-links/__tests__/KButton.spec.js @@ -66,7 +66,7 @@ describe('KButton', () => { }); }); - describe('[Visual] KButton Visual Tests', () => { + describe.visual('KButton Visual Tests', () => { it('renders correctly with default props', async () => { await renderComponent('KButton', { text: 'Test Button' }); await takeSnapshot('KButton - Default'); diff --git a/package.json b/package.json index 3f25d10c0..a711214e3 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ "precompile-svgs": "node utils/precompileSvgs/index.js && yarn run pregenerate", "precompile-custom-svgs": "node utils/precompileSvgs/index.js --custom && yarn run pregenerate", "_lint-watch-fix": "yarn lint -w -m", - "test:percy": "PERCY_LOGLEVEL=info npx percy exec -v -- jest --config jest.conf/visual.index.js -i ./lib/buttons-and-links/__tests__/KButton.spec.js -t '\\[Visual\\]'", - "test": "jest --config=jest.conf/index.js -t '^(?!.*\\[Visual\\])'", + "test:percy": "PERCY_LOGLEVEL=info npx percy exec -v -- jest --config jest.conf/visual.index.js -i ./lib/buttons-and-links/__tests__/KButton.spec.js", + "test": "jest --config=jest.conf/index.js", "test:visual": "concurrently --kill-others --success first --names \"SERVER,TEST\" -c \"bgCyan.bold,bgYellow.bold\" \"yarn dev-only > /dev/null 2>&1\" \"yarn test:percy\"", "_api-watch": "chokidar \"**/lib/**\" -c \"node utils/extractApi.js\"" },