From a965dd5a7ca5ce6137d154465d27490a66cc77fe Mon Sep 17 00:00:00 2001 From: Nikita Barsukov Date: Tue, 1 Oct 2024 16:57:44 +0300 Subject: [PATCH] chore(demo-cypress): screenshot testing for component tests (#9290) --- .github/screenshot-bot.config.toml | 2 +- .github/workflows/e2e-playwright.yml | 2 +- .gitignore | 1 + package-lock.json | 239 ++++++++---------- package.json | 2 +- .../demo-cypress/cypress-image-diff.config.js | 9 + projects/demo-cypress/cypress.config.ts | 4 + projects/demo-cypress/package.json | 3 +- .../src/support/component-index.html | 5 +- .../demo-cypress/src/support/component.ts | 3 + .../src/tests/input-phone-international.cy.ts | 30 ++- projects/demo-cypress/tsconfig.json | 1 + projects/demo/package.json | 2 +- .../components/chip/examples/4/index.html | 2 +- .../combine-cypress-failed-screenshots.ts | 47 ++++ .../combine-playwright-failed-screenshots.ts | 27 +- scripts/visual-testing/combine-snapshots.ts | 28 ++ 17 files changed, 241 insertions(+), 166 deletions(-) create mode 100644 projects/demo-cypress/cypress-image-diff.config.js create mode 100644 scripts/visual-testing/combine-cypress-failed-screenshots.ts rename scripts/{ => visual-testing}/combine-playwright-failed-screenshots.ts (52%) create mode 100644 scripts/visual-testing/combine-snapshots.ts diff --git a/.github/screenshot-bot.config.toml b/.github/screenshot-bot.config.toml index 7451ce7fa1e0..a161201598bf 100644 --- a/.github/screenshot-bot.config.toml +++ b/.github/screenshot-bot.config.toml @@ -22,4 +22,4 @@ branchesIgnore = ["^release/.*", "^v[0-9].x$"] screenshotImageAttrs = [] # Text which is placed at the beginning of section "Failed tests" -failedTestsReportDescription = '**After <= Diff => Before**' +failedTestsReportDescription = '**Before <= Diff => After**' diff --git a/.github/workflows/e2e-playwright.yml b/.github/workflows/e2e-playwright.yml index dba9900f9638..b006c4942b20 100644 --- a/.github/workflows/e2e-playwright.yml +++ b/.github/workflows/e2e-playwright.yml @@ -74,7 +74,7 @@ jobs: - name: Combine images to get diff reports run: | npm install canvas - npx ts-node ./scripts/combine-playwright-failed-screenshots.ts + npx ts-node ./scripts/visual-testing/combine-playwright-failed-screenshots.ts - name: Debug output continue-on-error: true diff --git a/.gitignore b/.gitignore index 1d8f4f3cd00c..adda93a4193f 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ RELEASE_BODY.md *tsbuildinfo .angular .nx +/projects/demo-cypress/tests-results/ /projects/demo-playwright/tests-results/ /projects/demo-playwright/tests-report/ /projects/demo-playwright/snapshots/ diff --git a/package-lock.json b/package-lock.json index e9434a70b275..95691b5b865c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,7 @@ "ng-packagr": "16.2.3", "ngx-highlightjs": "10.0.0", "nx": "19.8.2", - "rxjs": "7.5.0", + "rxjs": "7.8.1", "standard-version": "9.5.0", "ts-mockito": "2.6.1", "ts-node": "10.9.2", @@ -405,16 +405,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular-devkit/architect/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/@angular-devkit/build-angular": { "version": "16.2.16", "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-16.2.16.tgz", @@ -666,16 +656,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/@angular-devkit/build-angular/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -769,16 +749,6 @@ "webpack-dev-server": "^4.0.0" } }, - "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/@angular-devkit/core": { "version": "16.2.16", "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.16.tgz", @@ -807,16 +777,6 @@ } } }, - "node_modules/@angular-devkit/core/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "devOptional": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/@angular-devkit/schematics": { "version": "16.2.16", "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.16.tgz", @@ -859,16 +819,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular-devkit/schematics/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "devOptional": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/@angular-eslint/bundled-angular-compiler": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.3.1.tgz", @@ -3817,7 +3767,6 @@ "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "dev": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.1.90" } @@ -9345,16 +9294,6 @@ "node": ">= 4" } }, - "node_modules/@nx/webpack/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/@nx/webpack/node_modules/sass-loader": { "version": "12.6.0", "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", @@ -17338,6 +17277,38 @@ "node": "^16.0.0 || ^18.0.0 || >=20.0.0" } }, + "node_modules/cypress-image-diff-js": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cypress-image-diff-js/-/cypress-image-diff-js-2.2.1.tgz", + "integrity": "sha512-ukZAiijQ54LLPefXDXfmscTcUn55QpB4LWEaxVEzZOlihHQyxGWzgT4cMO7jQ2d2rzwpIqxNWWUaAyjNHVyl/g==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@colors/colors": "^1.5.0", + "arg": "^4.1.1", + "cypress-recurse": "^1.13.1", + "fs-extra": "^9.0.1", + "handlebars": "^4.7.7", + "lodash": "^4.17.21", + "pixelmatch": "^5.1.0", + "pngjs": "^3.4.0" + }, + "bin": { + "cypress-image-diff": "bin/cypress-image-diff.js" + }, + "peerDependencies": { + "cypress": ">=9.6.1" + } + }, + "node_modules/cypress-recurse": { + "version": "1.35.3", + "resolved": "https://registry.npmjs.org/cypress-recurse/-/cypress-recurse-1.35.3.tgz", + "integrity": "sha512-NbFOpEuZT4tFqAB0jQqel7WtVNDe8pvSHE2TfXvYk4pspf3wq98OC2RhhLn3bMnoCnPtY4IHO7e37c+CZ9HnMA==", + "dev": true, + "dependencies": { + "humanize-duration": "^3.27.3" + } + }, "node_modules/cypress/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -24101,6 +24072,12 @@ "node": ">=8.12.0" } }, + "node_modules/humanize-duration": { + "version": "3.32.1", + "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.32.1.tgz", + "integrity": "sha512-inh5wue5XdfObhu/IGEMiA1nUXigSGcaKNemcbLRKa7jXYGDZXr3LoT9pTIzq2hPEbld7w/qv9h+ikWGz8fL1g==", + "dev": true + }, "node_modules/humanize-ms": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", @@ -24470,16 +24447,6 @@ "node": ">=8" } }, - "node_modules/inquirer/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/inquirer/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -28777,16 +28744,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/listr2/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -30848,16 +30805,6 @@ "node": ">=12" } }, - "node_modules/ng-packagr/node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, "node_modules/ngx-highlightjs": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/ngx-highlightjs/-/ngx-highlightjs-10.0.0.tgz", @@ -32692,6 +32639,27 @@ "nice-napi": "^1.0.2" } }, + "node_modules/pixelmatch": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.3.0.tgz", + "integrity": "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==", + "dev": true, + "dependencies": { + "pngjs": "^6.0.0" + }, + "bin": { + "pixelmatch": "bin/pixelmatch" + } + }, + "node_modules/pixelmatch/node_modules/pngjs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "dev": true, + "engines": { + "node": ">=12.13.0" + } + }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -32827,6 +32795,15 @@ "node": ">=4" } }, + "node_modules/pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/portfinder": { "version": "1.0.32", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz", @@ -35021,10 +34998,9 @@ "license": "Apache-2.0" }, "node_modules/rxjs": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.0.tgz", - "integrity": "sha512-fuCKAfFawVYX0pyFlETtYnXI+5iiY9Dftgk+VdgeOq+Qyi9ZDWckHZRDaXRt5WCNbbLkmAheoSGDiceyCIKNZA==", - "license": "Apache-2.0", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dependencies": { "tslib": "^2.1.0" } @@ -40481,8 +40457,8 @@ "@angular/common": ">=16.0.0", "@angular/core": ">=16.0.0", "@ng-web-apis/common": "^4.6.5", - "@taiga-ui/cdk": "^4.8.1", - "@taiga-ui/core": "^4.8.1", + "@taiga-ui/cdk": "^4.9.0", + "@taiga-ui/core": "^4.9.0", "@taiga-ui/polymorpheus": "^4.7.4", "tslib": "^2.7.0" } @@ -40499,10 +40475,10 @@ "@maskito/core": "^3.0.3", "@maskito/kit": "^3.0.3", "@ng-web-apis/common": "^4.6.5", - "@taiga-ui/cdk": "^4.8.1", - "@taiga-ui/core": "^4.8.1", - "@taiga-ui/i18n": "^4.8.1", - "@taiga-ui/kit": "^4.8.1", + "@taiga-ui/cdk": "^4.9.0", + "@taiga-ui/core": "^4.9.0", + "@taiga-ui/i18n": "^4.9.0", + "@taiga-ui/kit": "^4.9.0", "@taiga-ui/polymorpheus": "^4.7.4", "rxjs": ">=7.0.0", "tslib": "^2.7.0" @@ -40522,10 +40498,10 @@ "@angular/forms": ">=16.0.0", "@angular/router": ">=16.0.0", "@ng-web-apis/common": "^4.6.5", - "@taiga-ui/addon-mobile": "^4.8.1", - "@taiga-ui/cdk": "^4.8.1", - "@taiga-ui/core": "^4.8.1", - "@taiga-ui/kit": "^4.8.1", + "@taiga-ui/addon-mobile": "^4.9.0", + "@taiga-ui/cdk": "^4.9.0", + "@taiga-ui/core": "^4.9.0", + "@taiga-ui/kit": "^4.9.0", "@taiga-ui/polymorpheus": "^4.7.4", "markdown-it": ">=14.1.0", "ngx-highlightjs": ">=10.0.0", @@ -40541,9 +40517,9 @@ "@angular/common": ">=16.0.0", "@angular/core": ">=16.0.0", "@ng-web-apis/common": "^4.6.5", - "@taiga-ui/cdk": "^4.8.1", - "@taiga-ui/core": "^4.8.1", - "@taiga-ui/kit": "^4.8.1", + "@taiga-ui/cdk": "^4.9.0", + "@taiga-ui/core": "^4.9.0", + "@taiga-ui/kit": "^4.9.0", "@taiga-ui/polymorpheus": "^4.7.4", "rxjs": ">=7.0.0", "tslib": "^2.7.0" @@ -40557,10 +40533,10 @@ "@angular/common": ">=16.0.0", "@angular/core": ">=16.0.0", "@ng-web-apis/intersection-observer": "^4.6.5", - "@taiga-ui/cdk": "^4.8.1", - "@taiga-ui/core": "^4.8.1", - "@taiga-ui/i18n": "^4.8.1", - "@taiga-ui/kit": "^4.8.1", + "@taiga-ui/cdk": "^4.9.0", + "@taiga-ui/core": "^4.9.0", + "@taiga-ui/i18n": "^4.9.0", + "@taiga-ui/kit": "^4.9.0", "@taiga-ui/polymorpheus": "^4.7.4", "rxjs": ">=7.0.0", "tslib": "^2.7.0" @@ -40613,9 +40589,9 @@ "@angular/router": ">=16.0.0", "@ng-web-apis/common": "^4.6.5", "@ng-web-apis/mutation-observer": "^4.6.5", - "@taiga-ui/cdk": "^4.8.1", + "@taiga-ui/cdk": "^4.9.0", "@taiga-ui/event-plugins": "^4.2.4", - "@taiga-ui/i18n": "^4.8.1", + "@taiga-ui/i18n": "^4.9.0", "@taiga-ui/polymorpheus": "^4.7.4", "rxjs": ">=7.0.0", "tslib": "^2.7.0" @@ -40640,7 +40616,7 @@ "@stackblitz/sdk": "1.11.0", "@taiga-ui/dompurify": "4.1.7", "date-fns": "4.1.0", - "rxjs": "7.5.0" + "rxjs": "7.8.1" }, "devDependencies": { "@nguniversal/builders": "16.2.0", @@ -40653,7 +40629,8 @@ "name": "@taiga-ui/demo-cypress", "devDependencies": { "@nx/cypress": "19.8.2", - "cypress": "13.15.0" + "cypress": "13.15.0", + "cypress-image-diff-js": "2.2.1" } }, "projects/demo-playwright": { @@ -40669,10 +40646,10 @@ "peerDependencies": { "@angular/common": ">=16.0.0", "@angular/core": ">=16.0.0", - "@taiga-ui/addon-commerce": "^4.8.1", - "@taiga-ui/cdk": "^4.8.1", - "@taiga-ui/core": "^4.8.1", - "@taiga-ui/kit": "^4.8.1", + "@taiga-ui/addon-commerce": "^4.9.0", + "@taiga-ui/cdk": "^4.9.0", + "@taiga-ui/core": "^4.9.0", + "@taiga-ui/kit": "^4.9.0", "@taiga-ui/polymorpheus": "^4.7.4", "rxjs": ">=7.0.0", "tslib": "^2.7.0" @@ -40730,9 +40707,9 @@ "@ng-web-apis/intersection-observer": "^4.6.5", "@ng-web-apis/mutation-observer": "^4.6.5", "@ng-web-apis/resize-observer": "^4.6.5", - "@taiga-ui/cdk": "^4.8.1", - "@taiga-ui/core": "^4.8.1", - "@taiga-ui/i18n": "^4.8.1", + "@taiga-ui/cdk": "^4.9.0", + "@taiga-ui/core": "^4.9.0", + "@taiga-ui/i18n": "^4.9.0", "@taiga-ui/polymorpheus": "^4.7.4", "rxjs": ">=7.0.0", "tslib": "^2.7.0" @@ -40745,9 +40722,9 @@ "peerDependencies": { "@angular/common": ">=16.0.0", "@angular/core": ">=16.0.0", - "@taiga-ui/cdk": "^4.8.1", - "@taiga-ui/core": "^4.8.1", - "@taiga-ui/kit": "^4.8.1", + "@taiga-ui/cdk": "^4.9.0", + "@taiga-ui/core": "^4.9.0", + "@taiga-ui/kit": "^4.9.0", "@taiga-ui/polymorpheus": "^4.7.4", "rxjs": ">=7.0.0", "tslib": "^2.7.0" @@ -40766,8 +40743,8 @@ "name": "@taiga-ui/styles", "version": "4.9.0", "peerDependencies": { - "@taiga-ui/cdk": "^4.8.1", - "@taiga-ui/core": "^4.8.1", + "@taiga-ui/cdk": "^4.9.0", + "@taiga-ui/core": "^4.9.0", "tslib": "^2.7.0" } }, @@ -40779,7 +40756,7 @@ "@taiga-ui/cdk": "^4.9.0" }, "peerDependencies": { - "@taiga-ui/cdk": "^4.8.1", + "@taiga-ui/cdk": "^4.9.0", "tslib": "^2.7.0" } }, @@ -40793,7 +40770,7 @@ "ts-jest": "29.2.5" }, "peerDependencies": { - "@taiga-ui/cdk": "^4.8.1", + "@taiga-ui/cdk": "^4.9.0", "tslib": "^2.7.0" } } diff --git a/package.json b/package.json index 40a9234fbe68..487ee708ba11 100644 --- a/package.json +++ b/package.json @@ -156,7 +156,7 @@ "ng-packagr": "16.2.3", "ngx-highlightjs": "10.0.0", "nx": "19.8.2", - "rxjs": "7.5.0", + "rxjs": "7.8.1", "standard-version": "9.5.0", "ts-mockito": "2.6.1", "ts-node": "10.9.2", diff --git a/projects/demo-cypress/cypress-image-diff.config.js b/projects/demo-cypress/cypress-image-diff.config.js new file mode 100644 index 000000000000..d7f30e063186 --- /dev/null +++ b/projects/demo-cypress/cypress-image-diff.config.js @@ -0,0 +1,9 @@ +module.exports = { + ROOT_DIR: 'tests-results', + SCREENSHOTS_DIR: 'snapshots', + REPORT_DIR: '.', + JSON_REPORT: { + FILENAME: 'report-summary', + OVERWRITE: true, + }, +}; diff --git a/projects/demo-cypress/cypress.config.ts b/projects/demo-cypress/cypress.config.ts index 40cca3fc756b..30cf708387f4 100644 --- a/projects/demo-cypress/cypress.config.ts +++ b/projects/demo-cypress/cypress.config.ts @@ -1,5 +1,6 @@ import {nxComponentTestingPreset} from '@nx/angular/plugins/component-testing'; import {defineConfig} from 'cypress'; +import getCompareSnapshotsPlugin from 'cypress-image-diff-js/plugin'; const preset = nxComponentTestingPreset(__filename); @@ -44,5 +45,8 @@ export default defineConfig({ indexHtmlFile: 'src/support/component-index.html', specPattern: 'src/tests/**/*.cy.ts', experimentalSingleTabRunMode: true, + setupNodeEvents(on, config) { + return getCompareSnapshotsPlugin(on, config); + }, }, }); diff --git a/projects/demo-cypress/package.json b/projects/demo-cypress/package.json index d2c6260d72b5..7663bbc06fa3 100644 --- a/projects/demo-cypress/package.json +++ b/projects/demo-cypress/package.json @@ -3,6 +3,7 @@ "private": true, "devDependencies": { "@nx/cypress": "19.8.2", - "cypress": "13.15.0" + "cypress": "13.15.0", + "cypress-image-diff-js": "2.2.1" } } diff --git a/projects/demo-cypress/src/support/component-index.html b/projects/demo-cypress/src/support/component-index.html index 39ca75702d5f..6bbf3e4c8754 100644 --- a/projects/demo-cypress/src/support/component-index.html +++ b/projects/demo-cypress/src/support/component-index.html @@ -13,6 +13,9 @@ Components App -
+
diff --git a/projects/demo-cypress/src/support/component.ts b/projects/demo-cypress/src/support/component.ts index fa2112b67934..5d1746f752a7 100644 --- a/projects/demo-cypress/src/support/component.ts +++ b/projects/demo-cypress/src/support/component.ts @@ -1,4 +1,7 @@ import {mount} from 'cypress/angular'; +import addCompareSnapshotCommand from 'cypress-image-diff-js/command'; + +addCompareSnapshotCommand(); declare global { namespace Cypress { diff --git a/projects/demo-cypress/src/tests/input-phone-international.cy.ts b/projects/demo-cypress/src/tests/input-phone-international.cy.ts index ca28b5258d85..fe35c7b6701f 100644 --- a/projects/demo-cypress/src/tests/input-phone-international.cy.ts +++ b/projects/demo-cypress/src/tests/input-phone-international.cy.ts @@ -11,7 +11,7 @@ import { import {takeUntilDestroyed} from '@angular/core/rxjs-interop'; import {FormControl, ReactiveFormsModule} from '@angular/forms'; import {provideAnimations} from '@angular/platform-browser/animations'; -import {TuiRoot} from '@taiga-ui/core'; +import {TUI_ANIMATIONS_SPEED, TuiIcon, TuiRoot} from '@taiga-ui/core'; import type {TuiCountryIsoCode} from '@taiga-ui/i18n'; import { TuiInputPhoneInternational, @@ -21,19 +21,22 @@ import {createOutputSpy} from 'cypress/angular'; @Component({ standalone: true, - imports: [ReactiveFormsModule, TuiInputPhoneInternational, TuiRoot], + imports: [ReactiveFormsModule, TuiIcon, TuiInputPhoneInternational, TuiRoot], template: ` + > + + `, changeDetection: ChangeDetectionStrategy.OnPush, providers: [ provideAnimations(), + {provide: TUI_ANIMATIONS_SPEED, useValue: 0}, tuiInputPhoneInternationalOptionsProvider({ metadata: import('libphonenumber-js/min/metadata').then((m) => m.default), }), @@ -249,6 +252,27 @@ describe('InputPhoneInternational', () => { }); }); }); + + describe('debug screenshot testing', () => { + beforeEach(() => { + cy.viewport(400, 300); + + cy.mount(Test, { + componentProperties: { + countryIsoCode: 'US', + }, + }); + }); + + it('entire page', () => { + cy.get('tui-input-phone-international').click('left'); + cy.compareSnapshot('entire-page'); + }); + + it('only textfield', () => { + cy.get('tui-input-phone-international').compareSnapshot('only-textfield'); + }); + }); }); function initAliases(wrapperSelector: string): void { diff --git a/projects/demo-cypress/tsconfig.json b/projects/demo-cypress/tsconfig.json index 08eff273ad88..5b0cf0cf718d 100644 --- a/projects/demo-cypress/tsconfig.json +++ b/projects/demo-cypress/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "moduleResolution": "bundler", "typeRoots": ["../../node_modules/@types", "../../node_modules/cypress/types"], "types": ["cypress", "node"] }, diff --git a/projects/demo/package.json b/projects/demo/package.json index 8e2538143eb3..8f7489920796 100644 --- a/projects/demo/package.json +++ b/projects/demo/package.json @@ -18,7 +18,7 @@ "@stackblitz/sdk": "1.11.0", "@taiga-ui/dompurify": "4.1.7", "date-fns": "4.1.0", - "rxjs": "7.5.0" + "rxjs": "7.8.1" }, "devDependencies": { "@nguniversal/builders": "16.2.0", diff --git a/projects/demo/src/modules/components/chip/examples/4/index.html b/projects/demo/src/modules/components/chip/examples/4/index.html index c83da4559011..190f7ac64bcd 100644 --- a/projects/demo/src/modules/components/chip/examples/4/index.html +++ b/projects/demo/src/modules/components/chip/examples/4/index.html @@ -3,7 +3,7 @@ class="fade" >
Very long value in chip
-
{{ 123435 | tuiAmount: 'RUB' | async }}
+
{{ 123456 | tuiAmount: 'RUB' | async }}
; +} + +(async function combineCypressFailedScreenshots(): Promise { + const reportSummary = readJSON(`${TEST_RESULTS_PATH}/report-summary.json`); + + if (!reportSummary) { + return; + } + + const failedTestSnapshots = reportSummary.suites + .map((x) => x.tests) + .flat() + .filter((x) => x.status === 'fail' && x.diffPath); + + for (const {baselinePath, diffPath, comparisonPath, name} of failedTestSnapshots) { + const buffer = await combineSnapshots( + [baselinePath, diffPath, comparisonPath].map((x) => `${ROOT_PATH}/${x}`), + ); + + writeFileSync(`${TEST_RESULTS_PATH}/${name}.diff.png`, buffer); + } +})(); + +function readJSON(path: string): T | null { + try { + return JSON.parse(readFileSync(path, 'utf-8')); + } catch { + return null; + } +} diff --git a/scripts/combine-playwright-failed-screenshots.ts b/scripts/visual-testing/combine-playwright-failed-screenshots.ts similarity index 52% rename from scripts/combine-playwright-failed-screenshots.ts rename to scripts/visual-testing/combine-playwright-failed-screenshots.ts index 033906de7466..31a73529e868 100644 --- a/scripts/combine-playwright-failed-screenshots.ts +++ b/scripts/visual-testing/combine-playwright-failed-screenshots.ts @@ -1,18 +1,10 @@ -// @ts-nocheck It is used in CI only! -/** - * Canvas has difficult installation guide for ARM CPU, including an Apple M1 or M2 - * (not friendly for our external contributors). - * https://github.com/Automattic/node-canvas/issues/1511 - */ import {readdirSync, writeFileSync} from 'node:fs'; -import {createCanvas, loadImage, version} from 'canvas'; +import {combineSnapshots} from './combine-snapshots'; const FAILED_SCREENSHOTS_PATH = 'projects/demo-playwright/tests-results'; const DIFF_IMAGE_POSTFIX = '-diff.png'; -console.info('canvas:', version); - (async function combinePlaywrightFailedScreenshots( rootPath = FAILED_SCREENSHOTS_PATH, ): Promise { @@ -35,22 +27,7 @@ console.info('canvas:', version); return; } - const images = await Promise.all(imagesPaths.map(loadImage)); - const totalWidth = images.reduce((acc: number, {width}) => acc + width, 0); - const maxHeight = Math.max(...images.map(({height}) => height)); - const canvas = createCanvas(totalWidth, maxHeight); - const ctx = canvas.getContext('2d'); - - let prevWidth = 0; - - images - .reverse() // After <= Diff => Before - .forEach((image) => { - ctx.drawImage(image, prevWidth, 0); - prevWidth += image.width; - }); - - const buffer = canvas.toBuffer('image/png'); + const buffer = await combineSnapshots(imagesPaths); const diffImageName = diffImage.split('/').pop()!.replace(DIFF_IMAGE_POSTFIX, ''); writeFileSync(`${rootPath}/${diffImageName}.diff.png`, buffer); diff --git a/scripts/visual-testing/combine-snapshots.ts b/scripts/visual-testing/combine-snapshots.ts new file mode 100644 index 000000000000..b9d69debb545 --- /dev/null +++ b/scripts/visual-testing/combine-snapshots.ts @@ -0,0 +1,28 @@ +// @ts-nocheck It is used in CI only! +/** + * Canvas has difficult installation guide for ARM CPU, including an Apple M1 or M2 + * (not friendly for our external contributors). + * https://github.com/Automattic/node-canvas/issues/1511 + */ +import {createCanvas, loadImage, version} from 'canvas'; + +export async function combineSnapshots( + imagesPaths: string[], +): Promise { + console.info('canvas:', version); + + const images = await Promise.all(imagesPaths.map(loadImage)); + const totalWidth = images.reduce((acc: number, {width}) => acc + width, 0); + const maxHeight = Math.max(...images.map(({height}) => height)); + const canvas = createCanvas(totalWidth, maxHeight); + const ctx = canvas.getContext('2d'); + + let prevWidth = 0; + + images.forEach((image) => { + ctx.drawImage(image, prevWidth, 0); + prevWidth += image.width; + }); + + return canvas.toBuffer('image/png'); +}