From 61a14d6a1e045b1f02ec90b24759624b34a0cf67 Mon Sep 17 00:00:00 2001 From: vagusX Date: Mon, 18 Dec 2023 14:25:40 +0800 Subject: [PATCH 01/19] ci: exit with 1 when bad cases existing (#46503) --- .../visual-regression-diff-build.yml | 3 +- .../visual-regression-diff-finish.yml | 2 +- .../visual-regression-persist-finish.yml | 2 - scripts/visual-regression/build.ts | 82 ++++++++++++------- 4 files changed, 55 insertions(+), 34 deletions(-) diff --git a/.github/workflows/visual-regression-diff-build.yml b/.github/workflows/visual-regression-diff-build.yml index 71127751cc..e7a698f8a9 100644 --- a/.github/workflows/visual-regression-diff-build.yml +++ b/.github/workflows/visual-regression-diff-build.yml @@ -93,6 +93,7 @@ jobs: # Upload report in `visualRegressionReport` - name: upload report artifact uses: actions/upload-artifact@v3 + if: ${{ always() }} with: name: visual-regression-report path: visualRegressionReport.tar.gz @@ -100,7 +101,7 @@ jobs: # Upload git ref for next workflow `visual-regression-diff-finish` use - name: Save persist key if: ${{ always() }} - # should be pr id + # should be pr id run: echo ${{ github.event.number }} > ./visual-regression-pr-id.txt - name: Upload persist key diff --git a/.github/workflows/visual-regression-diff-finish.yml b/.github/workflows/visual-regression-diff-finish.yml index 73a945afaf..2702422d4f 100644 --- a/.github/workflows/visual-regression-diff-finish.yml +++ b/.github/workflows/visual-regression-diff-finish.yml @@ -127,7 +127,7 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} body: | - ## Visual-Regression Diff Failed + ## Visual Regression Build for PR #${{ steps.pr.outputs.id }} Failed ❌ Visual-diff report job conclusion: ${{ fromJSON(needs.upstream-workflow-summary.outputs.job-status) }} body-include: '' diff --git a/.github/workflows/visual-regression-persist-finish.yml b/.github/workflows/visual-regression-persist-finish.yml index ad27da768f..e096bed452 100644 --- a/.github/workflows/visual-regression-persist-finish.yml +++ b/.github/workflows/visual-regression-persist-finish.yml @@ -87,8 +87,6 @@ jobs: - name: Persist Image Snapshot to OSS if: github.event.workflow_run.event == 'push' && (github.event.workflow_run.head_branch == 'master' || github.event.workflow_run.head_branch == 'feature') - id: persist - continue-on-error: true env: ALI_OSS_AK_ID: ${{ secrets.ALI_OSS_AK_ID }} ALI_OSS_AK_SECRET: ${{ secrets.ALI_OSS_AK_SECRET }} diff --git a/scripts/visual-regression/build.ts b/scripts/visual-regression/build.ts index 93014077c4..8cb0f6a4d3 100644 --- a/scripts/visual-regression/build.ts +++ b/scripts/visual-regression/build.ts @@ -63,7 +63,7 @@ const compareScreenshots = async ( diffPng.pack().pipe(fs.createWriteStream(diffImagePath)); } - return (mismatchedPixels / (targetWidth * targetHeight)) * 100; + return mismatchedPixels / (targetWidth * targetHeight); }; const readPngs = (dir: string) => fs.readdirSync(dir).filter((n) => n.endsWith('.png')); @@ -108,6 +108,10 @@ async function downloadBaseSnapshots(ref: string, targetDir: string) { interface IBadCase { type: 'removed' | 'changed'; filename: string; + /** + * 0 - 1 + */ + weight: number; } function md2Html(md: string) { @@ -135,12 +139,14 @@ function generateReport( ): [string, string] { const publicPath = isLocalEnv ? path.resolve(__dirname, '../..') : `${ossDomain}/pr-${prId}`; + const passed = badCases.length === 0; + const commonHeader = ` -## Visual Regression Report for PR #${prId} +## Visual Regression Report for PR #${prId} ${passed ? 'Passed ✅' : 'Failed ❌'} > **Target branch:** ${targetBranch} (${targetRef}) `.trim(); - if (badCases.length === 0) { + if (passed) { const mdStr = [ commonHeader, '------------------------', @@ -213,6 +219,7 @@ async function boot() { const baseImgSourceDir = path.resolve(__dirname, `../../imageSnapshots-${targetBranch}`); + /* --- prepare stage --- */ console.log( chalk.green( `Preparing image snapshots from latest \`${targetBranch}\` branch for pr \`${prId}\`\n`, @@ -220,11 +227,11 @@ async function boot() { ); await fse.ensureDir(baseImgSourceDir); - const targetRef = await getBranchLatestRef(targetBranch); - assert(targetRef, `Missing ref from ${targetBranch}`); + const targetCommitSha = await getBranchLatestRef(targetBranch); + assert(targetCommitSha, `Missing commit sha from ${targetBranch}`); if (!isLocalEnv) { - await downloadBaseSnapshots(targetRef, baseImgSourceDir); + await downloadBaseSnapshots(targetCommitSha, baseImgSourceDir); } else if (!fse.existsSync(baseImgSourceDir)) { console.log( chalk.yellow( @@ -252,24 +259,8 @@ async function boot() { console.log('\n'); const baseImgFileList = readPngs(baseImgSourceDir); - const currentImgFileList = readPngs(currentImgSourceDir); - - const deletedImgs = _.difference(baseImgFileList, currentImgFileList); - if (deletedImgs.length) { - console.log( - chalk.red('⛔️ Missing images compare to %s:\n%s'), - targetBranch, - prettyList(deletedImgs), - ); - console.log('\n'); - } - // ignore new images - const newImgs = _.difference(currentImgFileList, baseImgFileList); - if (newImgs.length) { - console.log(chalk.green('🆕 Added images:\n'), prettyList(newImgs)); - console.log('\n'); - } + /* --- compare stage --- */ const badCases: IBadCase[] = []; // compare cssinjs and css-var png from pr @@ -295,6 +286,7 @@ async function boot() { badCases.push({ type: 'removed', filename: compareImgName, + weight: 1, }); await fse.copy(baseImgPath, path.join(baseImgReportDir, compareImgName)); continue; @@ -310,7 +302,7 @@ async function boot() { console.log( 'Mismatched pixels for:', chalk.yellow(compareImgName), - `${mismatchedPxPercent.toFixed(2)}%\n`, + `${(mismatchedPxPercent * 100).toFixed(2)}%\n`, ); // copy compare imgs(x2) to report dir await fse.copy(baseImgPath, path.join(baseImgReportDir, compareImgName)); @@ -319,6 +311,7 @@ async function boot() { badCases.push({ type: 'changed', filename: compareImgName, + weight: mismatchedPxPercent, }); } else { console.log('Passed for: %s\n', chalk.green(compareImgName)); @@ -326,15 +319,16 @@ async function boot() { } } - if (badCases.length) { - console.log(chalk.red('⛔️ Failed cases:\n'), prettyList(badCases.map((i) => i.filename))); - console.log('\n'); - } - + /* --- generate report stage --- */ const jsonl = badCases.map((i) => JSON.stringify(i)).join('\n'); // write jsonl and markdown report to diffImgDir await fse.writeFile(path.join(reportDir, './report.jsonl'), jsonl); - const [reportMdStr, reportHtmlStr] = generateReport(badCases, targetBranch, targetRef, prId); + const [reportMdStr, reportHtmlStr] = generateReport( + badCases, + targetBranch, + targetCommitSha, + prId, + ); await fse.writeFile(path.join(reportDir, './report.md'), reportMdStr); const htmlTemplate = await fse.readFile(path.join(__dirname, './report-template.html'), 'utf8'); @@ -353,6 +347,34 @@ async function boot() { }, await fse.readdir(reportDir), ); + + const currentImgFileList = readPngs(currentImgSourceDir); + /* --- text report stage --- */ + console.log( + chalk.blue(`📊 Text report from pr #${prId} comparing to ${targetBranch}@${targetCommitSha}\n`), + ); + // new images + const newImgs = _.difference(currentImgFileList, baseImgFileList); + if (newImgs.length) { + console.log(chalk.green(`🆕 ${newImgs.length} images added from this pr`)); + console.log(chalk.green('🆕 Added images list:\n'), prettyList(newImgs)); + console.log('\n'); + } + + if (!badCases.length) { + console.log(chalk.green('🎉 All passed!')); + console.log('\n'); + return; + } + + const sortedBadCases = badCases.sort((a, b) => b.weight - a.weight); + console.log( + chalk.red('⛔️ Failed cases:\n'), + prettyList(sortedBadCases.map((i) => `[${i.type}] ${i.filename}`)), + ); + console.log('\n'); + // let job failed + process.exit(1); } boot(); From 49e60459d9075abb3d3fa023c1cc9306200188d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=B8=85?= Date: Mon, 18 Dec 2023 15:16:01 +0800 Subject: [PATCH 02/19] docs: add 5.12.3 changelog (#46505) * docs: add 5.12.3 changelog * remove : * update * merge * remove --- CHANGELOG.en-US.md | 14 ++++++++++++++ CHANGELOG.zh-CN.md | 14 ++++++++++++++ package.json | 2 +- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index 591ea9ef85..2a956bb0ad 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -16,6 +16,20 @@ tag: vVERSION --- +## 5.12.3 + +`2023-12-18` + +- 💄 修复 Tag 组件在 SSR 场景下的样式丢失问题。[#46500](https://github.com/ant-design/ant-design/pull/46500) [@MadCcc](https://github.com/MadCcc) +- 🐞 Upload 的 `disabled` 属性不再对下载按钮生效。[#46454](https://github.com/ant-design/ant-design/pull/46454) +- 💄 Upload.Dragger 增加一个水平内边距。[#46457](https://github.com/ant-design/ant-design/pull/46457) +- 🐞 修复 Upload `actions` 的颜色问题。[#46456](https://github.com/ant-design/ant-design/pull/46456) +- 🐞 修复 Form 使用 `getValueProps` 展示值无法更新的问题。[#46445](https://github.com/ant-design/ant-design/pull/46445) +- 💄 修复 Checkbox 自定义 `token.lineWidth` 时勾选箭头错位问题。[#46431](https://github.com/ant-design/ant-design/pull/46431) +- 🐞 修复 Select 组件定制 token 会让 padding 失效的问题。[#46427](https://github.com/ant-design/ant-design/pull/46427) [@MadCcc](https://github.com/MadCcc) +- 🐞 修复 Message 在 `cssVar` 模式下覆盖组件 token 无效的问题。[#46415](https://github.com/ant-design/ant-design/pull/46415) [@MadCcc](https://github.com/MadCcc) +- 💄 Flex 组件不应该应用额外的样式。[#46404](https://github.com/ant-design/ant-design/pull/46404) [@li-jia-nan](https://github.com/li-jia-nan) + ## 5.12.2 `2023-12-11` diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index 8a876d385a..362d20a77e 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -16,6 +16,20 @@ tag: vVERSION --- +## 5.12.3 + +`2023-12-18` + +- 💄 Fix Tag that style would be missing in SSR. [#46500](https://github.com/ant-design/ant-design/pull/46500) [@MadCcc](https://github.com/MadCcc) +- 🐞 Upload `disabled` prop should not affect download icon. [#46454](https://github.com/ant-design/ant-design/pull/46454) +- 💄 Upload.Dragger add vertical padding style. [#46457](https://github.com/ant-design/ant-design/pull/46457) +- 🐞 Fix Upload actions color issue. [#46456](https://github.com/ant-design/ant-design/pull/46456) +- 🐞 Fix Form with `getValueProps` not working with value update. [#46445](https://github.com/ant-design/ant-design/pull/46445) +- 💄 Fix Checkbox style when customize `token.lineWidth`. [#46431](https://github.com/ant-design/ant-design/pull/46431) +- 🐞 Fix Select that custom token make `padding` broken. [#46427](https://github.com/ant-design/ant-design/pull/46427) [@MadCcc](https://github.com/MadCcc) +- 🐞 Fix Message that token overrides not work in `cssVar` mode. [#46415](https://github.com/ant-design/ant-design/pull/46415) [@MadCcc](https://github.com/MadCcc) +- 💄 Fix Flex component don't apply extra style. [#46404](https://github.com/ant-design/ant-design/pull/46404) [@li-jia-nan](https://github.com/li-jia-nan) + ## 5.12.2 `2023-12-11` diff --git a/package.json b/package.json index a6d38f9ab7..50b43dff70 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "antd", - "version": "5.12.2", + "version": "5.12.3", "description": "An enterprise-class UI design language and React components implementation", "keywords": [ "ant", From 0d1bf57aef992ce4520987e6ad9a465978da1d09 Mon Sep 17 00:00:00 2001 From: Eloi0424 Date: Mon, 18 Dec 2023 15:55:28 +0800 Subject: [PATCH 03/19] docs: Input.Password onVisibleChange type (#46504) --- components/input/index.en-US.md | 2 +- components/input/index.zh-CN.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/input/index.en-US.md b/components/input/index.en-US.md index 55520e2425..2e3c34323a 100644 --- a/components/input/index.en-US.md +++ b/components/input/index.en-US.md @@ -124,7 +124,7 @@ Supports all props of `Input`. | Property | Description | Type | Default | Version | | --- | --- | --- | --- | --- | | visible | Whether the password is show or hide | boolean | false | 4.24.0 | -| onVisibleChange | Callback executed when visibility of the password is changed | boolean | - | 4.24.0 | +| onVisibleChange | Callback executed when visibility of the password is changed | (visible) => void | - | 4.24.0 | #### Input Methods diff --git a/components/input/index.zh-CN.md b/components/input/index.zh-CN.md index 22778624db..43e2663788 100644 --- a/components/input/index.zh-CN.md +++ b/components/input/index.zh-CN.md @@ -122,10 +122,10 @@ interface CountConfig { #### VisibilityToggle -| Property | Description | Type | Default | Version | -| --------------- | -------------------- | ------- | ------- | ------- | -| visible | 用于手动控制密码显隐 | boolean | false | 4.24 | -| onVisibleChange | 显隐密码的回调 | boolean | - | 4.24 | +| Property | Description | Type | Default | Version | +| --------------- | -------------------- | ----------------- | ------- | ------- | +| visible | 用于手动控制密码显隐 | boolean | false | 4.24 | +| onVisibleChange | 显隐密码的回调 | (visible) => void | - | 4.24 | #### Input Methods From c920c9df07ccf8a04f6f0d1b4e42e924219af73b Mon Sep 17 00:00:00 2001 From: vagusX Date: Mon, 18 Dec 2023 17:10:22 +0800 Subject: [PATCH 04/19] ci: fix failed comment stage for visual-diff (#46510) --- .github/workflows/visual-regression-diff-finish.yml | 4 +++- scripts/visual-regression/build.ts | 9 ++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/visual-regression-diff-finish.yml b/.github/workflows/visual-regression-diff-finish.yml index 2702422d4f..43c1925130 100644 --- a/.github/workflows/visual-regression-diff-finish.yml +++ b/.github/workflows/visual-regression-diff-finish.yml @@ -128,7 +128,9 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} body: | ## Visual Regression Build for PR #${{ steps.pr.outputs.id }} Failed ❌ - Visual-diff report job conclusion: ${{ fromJSON(needs.upstream-workflow-summary.outputs.job-status) }} + Potential causes: + - `upstream workflow` status: ${{ needs.upstream-workflow-summary.outputs.job-status }} + - `report upload` status: ${{ steps.report.outcome }} body-include: '' number: ${{ steps.pr.outputs.id }} diff --git a/scripts/visual-regression/build.ts b/scripts/visual-regression/build.ts index 8cb0f6a4d3..27e5842318 100644 --- a/scripts/visual-regression/build.ts +++ b/scripts/visual-regression/build.ts @@ -357,7 +357,8 @@ async function boot() { const newImgs = _.difference(currentImgFileList, baseImgFileList); if (newImgs.length) { console.log(chalk.green(`🆕 ${newImgs.length} images added from this pr`)); - console.log(chalk.green('🆕 Added images list:\n'), prettyList(newImgs)); + console.log(chalk.green('🆕 Added images list:\n')); + console.log(prettyList(newImgs)); console.log('\n'); } @@ -368,10 +369,8 @@ async function boot() { } const sortedBadCases = badCases.sort((a, b) => b.weight - a.weight); - console.log( - chalk.red('⛔️ Failed cases:\n'), - prettyList(sortedBadCases.map((i) => `[${i.type}] ${i.filename}`)), - ); + console.log(chalk.red('⛔️ Failed cases:\n')); + console.log(prettyList(sortedBadCases.map((i) => `[${i.type}] ${i.filename}`))); console.log('\n'); // let job failed process.exit(1); From 6a0e8a6c9c6c290f80677444ae136283ec5da414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=B8=85?= Date: Mon, 18 Dec 2023 21:02:20 +0800 Subject: [PATCH 05/19] chore: fix changelog doc error (#46514) --- CHANGELOG.en-US.md | 18 +++++++++--------- CHANGELOG.zh-CN.md | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index 2a956bb0ad..7590492a64 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -20,15 +20,15 @@ tag: vVERSION `2023-12-18` -- 💄 修复 Tag 组件在 SSR 场景下的样式丢失问题。[#46500](https://github.com/ant-design/ant-design/pull/46500) [@MadCcc](https://github.com/MadCcc) -- 🐞 Upload 的 `disabled` 属性不再对下载按钮生效。[#46454](https://github.com/ant-design/ant-design/pull/46454) -- 💄 Upload.Dragger 增加一个水平内边距。[#46457](https://github.com/ant-design/ant-design/pull/46457) -- 🐞 修复 Upload `actions` 的颜色问题。[#46456](https://github.com/ant-design/ant-design/pull/46456) -- 🐞 修复 Form 使用 `getValueProps` 展示值无法更新的问题。[#46445](https://github.com/ant-design/ant-design/pull/46445) -- 💄 修复 Checkbox 自定义 `token.lineWidth` 时勾选箭头错位问题。[#46431](https://github.com/ant-design/ant-design/pull/46431) -- 🐞 修复 Select 组件定制 token 会让 padding 失效的问题。[#46427](https://github.com/ant-design/ant-design/pull/46427) [@MadCcc](https://github.com/MadCcc) -- 🐞 修复 Message 在 `cssVar` 模式下覆盖组件 token 无效的问题。[#46415](https://github.com/ant-design/ant-design/pull/46415) [@MadCcc](https://github.com/MadCcc) -- 💄 Flex 组件不应该应用额外的样式。[#46404](https://github.com/ant-design/ant-design/pull/46404) [@li-jia-nan](https://github.com/li-jia-nan) +- 💄 Fix Tag that style would be missing in SSR. [#46500](https://github.com/ant-design/ant-design/pull/46500) [@MadCcc](https://github.com/MadCcc) +- 🐞 Upload `disabled` prop should not affect download icon. [#46454](https://github.com/ant-design/ant-design/pull/46454) +- 💄 Upload.Dragger add vertical padding style. [#46457](https://github.com/ant-design/ant-design/pull/46457) +- 🐞 Fix Upload actions color issue. [#46456](https://github.com/ant-design/ant-design/pull/46456) +- 🐞 Fix Form with `getValueProps` not working with value update. [#46445](https://github.com/ant-design/ant-design/pull/46445) +- 💄 Fix Checkbox style when customize `token.lineWidth`. [#46431](https://github.com/ant-design/ant-design/pull/46431) +- 🐞 Fix Select that custom token make `padding` broken. [#46427](https://github.com/ant-design/ant-design/pull/46427) [@MadCcc](https://github.com/MadCcc) +- 🐞 Fix Message that token overrides not work in `cssVar` mode. [#46415](https://github.com/ant-design/ant-design/pull/46415) [@MadCcc](https://github.com/MadCcc) +- 💄 Fix Flex component don't apply extra style. [#46404](https://github.com/ant-design/ant-design/pull/46404) [@li-jia-nan](https://github.com/li-jia-nan) ## 5.12.2 diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index 362d20a77e..cc5346d9bd 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -20,15 +20,15 @@ tag: vVERSION `2023-12-18` -- 💄 Fix Tag that style would be missing in SSR. [#46500](https://github.com/ant-design/ant-design/pull/46500) [@MadCcc](https://github.com/MadCcc) -- 🐞 Upload `disabled` prop should not affect download icon. [#46454](https://github.com/ant-design/ant-design/pull/46454) -- 💄 Upload.Dragger add vertical padding style. [#46457](https://github.com/ant-design/ant-design/pull/46457) -- 🐞 Fix Upload actions color issue. [#46456](https://github.com/ant-design/ant-design/pull/46456) -- 🐞 Fix Form with `getValueProps` not working with value update. [#46445](https://github.com/ant-design/ant-design/pull/46445) -- 💄 Fix Checkbox style when customize `token.lineWidth`. [#46431](https://github.com/ant-design/ant-design/pull/46431) -- 🐞 Fix Select that custom token make `padding` broken. [#46427](https://github.com/ant-design/ant-design/pull/46427) [@MadCcc](https://github.com/MadCcc) -- 🐞 Fix Message that token overrides not work in `cssVar` mode. [#46415](https://github.com/ant-design/ant-design/pull/46415) [@MadCcc](https://github.com/MadCcc) -- 💄 Fix Flex component don't apply extra style. [#46404](https://github.com/ant-design/ant-design/pull/46404) [@li-jia-nan](https://github.com/li-jia-nan) +- 💄 修复 Tag 组件在 SSR 场景下的样式丢失问题。[#46500](https://github.com/ant-design/ant-design/pull/46500) [@MadCcc](https://github.com/MadCcc) +- 🐞 Upload 的 `disabled` 属性不再对下载按钮生效。[#46454](https://github.com/ant-design/ant-design/pull/46454) +- 💄 Upload.Dragger 增加一个水平内边距。[#46457](https://github.com/ant-design/ant-design/pull/46457) +- 🐞 修复 Upload `actions` 的颜色问题。[#46456](https://github.com/ant-design/ant-design/pull/46456) +- 🐞 修复 Form 使用 `getValueProps` 展示值无法更新的问题。[#46445](https://github.com/ant-design/ant-design/pull/46445) +- 💄 修复 Checkbox 自定义 `token.lineWidth` 时勾选箭头错位问题。[#46431](https://github.com/ant-design/ant-design/pull/46431) +- 🐞 修复 Select 组件定制 token 会让 padding 失效的问题。[#46427](https://github.com/ant-design/ant-design/pull/46427) [@MadCcc](https://github.com/MadCcc) +- 🐞 修复 Message 在 `cssVar` 模式下覆盖组件 token 无效的问题。[#46415](https://github.com/ant-design/ant-design/pull/46415) [@MadCcc](https://github.com/MadCcc) +- 💄 Flex 组件不应该应用额外的样式。[#46404](https://github.com/ant-design/ant-design/pull/46404) [@li-jia-nan](https://github.com/li-jia-nan) ## 5.12.2 From 3c2205874c6e291be681b558ad9168aad0c699cb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 04:52:56 +0800 Subject: [PATCH 06/19] chore: upgrade deps (#46521) Co-authored-by: afc163 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 50b43dff70..8c686a562f 100644 --- a/package.json +++ b/package.json @@ -154,7 +154,7 @@ "rc-table": "~7.36.0", "rc-tabs": "~12.14.1", "rc-textarea": "~1.5.3", - "rc-tooltip": "~6.1.2", + "rc-tooltip": "~6.1.3", "rc-tree": "~5.8.2", "rc-tree-select": "~5.15.0", "rc-upload": "~4.3.5", From 3825cbca549c8e58a26c85f8ba79ebc82e61a995 Mon Sep 17 00:00:00 2001 From: vagusX Date: Tue, 19 Dec 2023 11:23:53 +0800 Subject: [PATCH 07/19] ci: avoid branch name injection (#46524) --- .github/workflows/visual-regression-diff-build.yml | 5 ++++- .github/workflows/visual-regression-diff-finish.yml | 3 ++- .github/workflows/visual-regression-persist-finish.yml | 6 ++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/visual-regression-diff-build.yml b/.github/workflows/visual-regression-diff-build.yml index e7a698f8a9..45c27a2d1e 100644 --- a/.github/workflows/visual-regression-diff-build.yml +++ b/.github/workflows/visual-regression-diff-build.yml @@ -87,8 +87,11 @@ jobs: # Execute visual regression diff task and zip then # output as visualRegressionReport.tar.gz - name: visual regression diff + env: + EVENT_NUMBER: ${{ github.event.number }} + BASE_REF: ${{ github.base_ref }} run: | - npm run visual-regression -- --pr-id=${{ github.event.number }} --base-ref=${{ github.base_ref}} + npm run visual-regression -- --pr-id=$EVENT_NUMBER --base-ref=$BASE_REF # Upload report in `visualRegressionReport` - name: upload report artifact diff --git a/.github/workflows/visual-regression-diff-finish.yml b/.github/workflows/visual-regression-diff-finish.yml index 43c1925130..53020a587f 100644 --- a/.github/workflows/visual-regression-diff-finish.yml +++ b/.github/workflows/visual-regression-diff-finish.yml @@ -92,6 +92,7 @@ jobs: env: ALI_OSS_AK_ID: ${{ secrets.ALI_OSS_AK_ID }} ALI_OSS_AK_SECRET: ${{ secrets.ALI_OSS_AK_SECRET }} + PR_ID: ${{ steps.pr.outputs.id }} run: | mkdir ./visualRegressionReport tar -xzvf visualRegressionReport.tar.gz -C ./visualRegressionReport @@ -102,7 +103,7 @@ jobs: echo "✅ Install `ali-oss` Finished" echo "🤖 Uploading" - node scripts/visual-regression/upload.js ./visualRegressionReport --ref=pr-${{ steps.pr.outputs.id }} + node scripts/visual-regression/upload.js ./visualRegressionReport --ref=pr-$PR_ID echo "✅ Uploaded" delimiter="$(openssl rand -hex 8)" diff --git a/.github/workflows/visual-regression-persist-finish.yml b/.github/workflows/visual-regression-persist-finish.yml index e096bed452..660a402a8e 100644 --- a/.github/workflows/visual-regression-persist-finish.yml +++ b/.github/workflows/visual-regression-persist-finish.yml @@ -90,13 +90,15 @@ jobs: env: ALI_OSS_AK_ID: ${{ secrets.ALI_OSS_AK_ID }} ALI_OSS_AK_SECRET: ${{ secrets.ALI_OSS_AK_SECRET }} + HEAD_SHA: ${{ github.event.workflow_run.head_sha }} + HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} run: | rm package.json npm i ali-oss --no-save echo "✅ Install `ali-oss` Finished" echo "🤖 Uploading" - node scripts/visual-regression/upload.js ./imageSnapshots.tar.gz --ref=${{ github.event.workflow_run.head_sha }} - node scripts/visual-regression/upload.js ./visual-regression-ref.txt --ref=${{ github.event.workflow_run.head_branch }} + node scripts/visual-regression/upload.js ./imageSnapshots.tar.gz --ref=$HEAD_SHA + node scripts/visual-regression/upload.js ./visual-regression-ref.txt --ref=$HEAD_BRANCH echo "✅ Uploaded" From b3956a9ba2c7526401dfa1714d67be250f4c6412 Mon Sep 17 00:00:00 2001 From: afc163 Date: Tue, 19 Dec 2023 12:38:09 +0800 Subject: [PATCH 08/19] docs: fix Rate demo type for strict mode (#46520) * docs: fix Rate demo type for strict mode * Apply suggestions from code review Co-authored-by: lijianan <574980606@qq.com> Signed-off-by: afc163 --------- Signed-off-by: afc163 Co-authored-by: lijianan <574980606@qq.com> --- components/rate/demo/character-function.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/rate/demo/character-function.tsx b/components/rate/demo/character-function.tsx index d36bd06454..0ac65a9025 100644 --- a/components/rate/demo/character-function.tsx +++ b/components/rate/demo/character-function.tsx @@ -12,9 +12,9 @@ const customIcons: Record = { const App: React.FC = () => ( <> - index + 1} /> + index + 1} />
- customIcons[index + 1]} /> + customIcons[index + 1]} /> ); From ce28f36adba03bcc77b8ad03f77576ad61afb4fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Long=20Hao=20=28=E9=BE=99=E6=BF=A0=29?= <45565100+LongHaoo@users.noreply.github.com> Date: Tue, 19 Dec 2023 13:53:36 +0800 Subject: [PATCH 09/19] docs: Update FormItem getValueProps desc (#46485) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 二货爱吃白萝卜 Co-authored-by: vagusX --- components/form/index.en-US.md | 2 +- components/form/index.zh-CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/form/index.en-US.md b/components/form/index.en-US.md index d54cfc65a4..4972cc60d4 100644 --- a/components/form/index.en-US.md +++ b/components/form/index.en-US.md @@ -123,7 +123,7 @@ Form field component for data bidirectional binding, validation, layout, and so | dependencies | Set the dependency field. See [below](#dependencies) | [NamePath](#namepath)\[] | - | | | extra | The extra prompt message. It is similar to help. Usage example: to display error message and prompt message at the same time | ReactNode | - | | | getValueFromEvent | Specify how to get value from event or other onChange arguments | (..args: any\[]) => any | - | | -| getValueProps | Additional props with sub component | (value: any) => any | - | 4.2.0 | +| getValueProps | Additional props with sub component (It's not recommended to generate dynamic function prop by `getValueProps`. Please pass it to child component directly) | (value: any) => Record | - | 4.2.0 | | hasFeedback | Used with `validateStatus`, this option specifies the validation status icon. Recommended to be used only with `Input`. Also, It can get feedback icons via icons prop. | boolean \| { icons: [FeedbackIcons](#feedbackicons) } | false | icons: 5.9.0 | | help | The prompt message. If not provided, the prompt message will be generated by the validation rule. | ReactNode | - | | | hidden | Whether to hide Form.Item (still collect and validate value) | boolean | false | 4.4.0 | diff --git a/components/form/index.zh-CN.md b/components/form/index.zh-CN.md index 6103714707..ba4e5a4a0a 100644 --- a/components/form/index.zh-CN.md +++ b/components/form/index.zh-CN.md @@ -124,7 +124,7 @@ const validateMessages = { | dependencies | 设置依赖字段,说明[见下](#dependencies) | [NamePath](#namepath)\[] | - | | | extra | 额外的提示信息,和 `help` 类似,当需要错误信息和提示文案同时出现时,可以使用这个。 | ReactNode | - | | | getValueFromEvent | 设置如何将 event 的值转换成字段值 | (..args: any\[]) => any | - | | -| getValueProps | 为子元素添加额外的属性 | (value: any) => any | - | 4.2.0 | +| getValueProps | 为子元素添加额外的属性 (不建议通过 `getValueProps` 生成动态函数 prop,请直接将其传递给子组件) | (value: any) => Record | - | 4.2.0 | | hasFeedback | 配合 `validateStatus` 属性使用,展示校验状态图标,建议只配合 Input 组件使用 此外,它还可以通过 Icons 属性获取反馈图标。 | boolean \| { icons: [FeedbackIcons](#feedbackicons) } | false | icons: 5.9.0 | | help | 提示信息,如不设置,则会根据校验规则自动生成 | ReactNode | - | | | hidden | 是否隐藏字段(依然会收集和校验字段) | boolean | false | 4.4.0 | From 37fd3273afb1fe078950a2923e3c0946eb3b15fe Mon Sep 17 00:00:00 2001 From: MadCcc Date: Tue, 19 Dec 2023 15:06:07 +0800 Subject: [PATCH 10/19] fix: DatePicker style in cssVar mode (#46526) --- components/date-picker/generatePicker/generateSinglePicker.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/components/date-picker/generatePicker/generateSinglePicker.tsx b/components/date-picker/generatePicker/generateSinglePicker.tsx index 2aab988c00..f834e3b73c 100644 --- a/components/date-picker/generatePicker/generateSinglePicker.tsx +++ b/components/date-picker/generatePicker/generateSinglePicker.tsx @@ -187,6 +187,7 @@ export default function generatePicker(generateConfig: GenerateConfig< dropdownClassName={classNames( hashId, cssVarCls, + rootCls, rootClassName, popupClassName || dropdownClassName, )} From 03ac98a4a09e5dcd2985840a30449875d8cf7956 Mon Sep 17 00:00:00 2001 From: MadCcc Date: Tue, 19 Dec 2023 19:09:24 +0800 Subject: [PATCH 11/19] docs: changelog 5.12.4 (#46532) --- CHANGELOG.en-US.md | 6 ++++++ CHANGELOG.zh-CN.md | 6 ++++++ package.json | 2 +- scripts/post-script.ts | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index 7590492a64..2a91ee5653 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -16,6 +16,12 @@ tag: vVERSION --- +## 5.12.4 + +`2023-12-19` + +- 🐞 Fix DatePicker style in `cssVar` mode. [#46526](https://github.com/ant-design/ant-design/pull/46526) + ## 5.12.3 `2023-12-18` diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index cc5346d9bd..bacab940c9 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -16,6 +16,12 @@ tag: vVERSION --- +## 5.12.4 + +`2023-12-19` + +- 🐞 修复 DatePicker 组件在 CSS 变量模式下的样式错乱问题。[#46526](https://github.com/ant-design/ant-design/pull/46526) + ## 5.12.3 `2023-12-18` diff --git a/package.json b/package.json index 8c686a562f..480aba0ef2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "antd", - "version": "5.12.3", + "version": "5.12.4", "description": "An enterprise-class UI design language and React components implementation", "keywords": [ "ant", diff --git a/scripts/post-script.ts b/scripts/post-script.ts index 082faa404f..5b33917b6f 100644 --- a/scripts/post-script.ts +++ b/scripts/post-script.ts @@ -52,6 +52,7 @@ const DEPRECIATED_VERSION = { '5.11.1': ['https://github.com/ant-design/ant-design/issues/45883'], '5.11.2': ['https://github.com/ant-design/ant-design/issues/46005'], '5.11.4': ['https://github.com/ant-design/ant-design/pull/46103'], + '5.12.3': ['https://github.com/ant-design/ant-design/issues/46525'], } as const; function matchDeprecated(v: string) { From e5d3288915d0891e4d75b0a39de8f7fc556ccd46 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 20:40:03 +0800 Subject: [PATCH 12/19] chore(deps-dev): bump open from 9.1.0 to 10.0.0 (#46534) Bumps [open](https://github.com/sindresorhus/open) from 9.1.0 to 10.0.0. - [Release notes](https://github.com/sindresorhus/open/releases) - [Commits](https://github.com/sindresorhus/open/compare/v9.1.0...v10.0.0) --- updated-dependencies: - dependency-name: open dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 480aba0ef2..aac032334c 100644 --- a/package.json +++ b/package.json @@ -275,7 +275,7 @@ "node-fetch": "^3.3.2", "node-notifier": "^10.0.1", "nprogress": "^0.2.0", - "open": "^9.1.0", + "open": "^10.0.0", "pixelmatch": "^5.3.0", "pngjs": "^7.0.0", "prettier": "^3.1.0", From 781028c069031f0c55bd4e60a9f89b3951276f3d Mon Sep 17 00:00:00 2001 From: vagusX Date: Wed, 20 Dec 2023 12:01:17 +0800 Subject: [PATCH 13/19] ci: fix download report artifact ignore visual-diff-build status (#46539) --- .../workflows/visual-regression-diff-finish.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/visual-regression-diff-finish.yml b/.github/workflows/visual-regression-diff-finish.yml index 53020a587f..f2723c3884 100644 --- a/.github/workflows/visual-regression-diff-finish.yml +++ b/.github/workflows/visual-regression-diff-finish.yml @@ -17,9 +17,7 @@ jobs: runs-on: ubuntu-latest outputs: jobs: ${{ steps.visual_diff_build_job_status.outputs.result }} - build-success: ${{ steps.visual_diff_build_job_status.outputs.build-success }} - build-failure: ${{ steps.visual_diff_build_job_status.outputs.build-failure }} - job-status: ${{ steps.visual_diff_build_job_status.outputs.job-status }} + build-status: ${{ steps.visual_diff_build_job_status.outputs.build-status }} steps: - name: summary jobs status uses: actions/github-script@v6 @@ -47,9 +45,7 @@ jobs: console.log('visual-diff report job status: %s', jobs['visual-diff report']); // set output - core.setOutput('build-success', jobs['visual-diff report'] === 'success'); - core.setOutput('build-failure', jobs['visual-diff report'] === 'failure'); - core.setOutput('job-status', jobs['visual-diff report']); + core.setOutput('build-status', jobs['visual-diff report']); return jobs; download-visual-regression-report: @@ -79,7 +75,8 @@ jobs: # Download report artifact - name: download report artifact - if: ${{ fromJSON(needs.upstream-workflow-summary.outputs.build-success) }} + id: download_report + if: ${{ fromJSON(needs.upstream-workflow-summary.outputs.build-status) == 'success' || fromJSON(needs.upstream-workflow-summary.outputs.build-status) == 'failure' }} uses: dawidd6/action-download-artifact@v2 with: workflow: ${{ github.event.workflow_run.workflow_id }} @@ -123,7 +120,7 @@ jobs: number: ${{ steps.pr.outputs.id }} - name: failed comment - if: ${{ fromJSON(needs.upstream-workflow-summary.outputs.build-failure) || steps.report.outcome == 'failure' || failure() }} + if: ${{ steps.download_report.outcome == 'failure' || steps.report.outcome == 'failure' || failure() }} uses: actions-cool/maintain-one-comment@v3 with: token: ${{ secrets.GITHUB_TOKEN }} @@ -131,6 +128,7 @@ jobs: ## Visual Regression Build for PR #${{ steps.pr.outputs.id }} Failed ❌ Potential causes: - `upstream workflow` status: ${{ needs.upstream-workflow-summary.outputs.job-status }} + - `download report artifact` status: ${{ steps.download_report.outcome }} - `report upload` status: ${{ steps.report.outcome }} body-include: '' From ddea828999aae1cb4714fbaac1964a26bc133c85 Mon Sep 17 00:00:00 2001 From: vagusX Date: Wed, 20 Dec 2023 13:45:46 +0800 Subject: [PATCH 14/19] ci: wrong usage for fromJSON (#46541) --- .github/workflows/visual-regression-diff-finish.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/visual-regression-diff-finish.yml b/.github/workflows/visual-regression-diff-finish.yml index f2723c3884..23689acc15 100644 --- a/.github/workflows/visual-regression-diff-finish.yml +++ b/.github/workflows/visual-regression-diff-finish.yml @@ -76,7 +76,7 @@ jobs: # Download report artifact - name: download report artifact id: download_report - if: ${{ fromJSON(needs.upstream-workflow-summary.outputs.build-status) == 'success' || fromJSON(needs.upstream-workflow-summary.outputs.build-status) == 'failure' }} + if: ${{ needs.upstream-workflow-summary.outputs.build-status == 'success' || needs.upstream-workflow-summary.outputs.build-status == 'failure' }} uses: dawidd6/action-download-artifact@v2 with: workflow: ${{ github.event.workflow_run.workflow_id }} @@ -127,7 +127,7 @@ jobs: body: | ## Visual Regression Build for PR #${{ steps.pr.outputs.id }} Failed ❌ Potential causes: - - `upstream workflow` status: ${{ needs.upstream-workflow-summary.outputs.job-status }} + - `upstream workflow` status: ${{ needs.upstream-workflow-summary.outputs.build-status }} - `download report artifact` status: ${{ steps.download_report.outcome }} - `report upload` status: ${{ steps.report.outcome }} From 5393d9ce36821e64590d3f0d07daa0d393a4c299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BA=A2?= Date: Wed, 20 Dec 2023 14:45:05 +0800 Subject: [PATCH 15/19] docs: clean up docs (#46542) no message --- README-zh_CN.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README-zh_CN.md b/README-zh_CN.md index 1e9685619f..a502e8a2c8 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -171,8 +171,6 @@ $ npm start ## 🤝 参与共建 [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) -ome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) - From b0712840270a6ef88d76de11f14c1361cab9d1c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E7=88=B1=E5=90=83=E7=99=BD=E8=90=9D?= =?UTF-8?q?=E5=8D=9C?= Date: Thu, 21 Dec 2023 10:07:52 +0800 Subject: [PATCH 16/19] docs: vite doc (#46550) --- docs/blog/build-ghost.en-US.md | 127 +++++++++++++++++++++++++++++++++ docs/blog/build-ghost.zh-CN.md | 127 +++++++++++++++++++++++++++++++++ 2 files changed, 254 insertions(+) create mode 100644 docs/blog/build-ghost.en-US.md create mode 100644 docs/blog/build-ghost.zh-CN.md diff --git a/docs/blog/build-ghost.en-US.md b/docs/blog/build-ghost.en-US.md new file mode 100644 index 0000000000..67bd97814b --- /dev/null +++ b/docs/blog/build-ghost.en-US.md @@ -0,0 +1,127 @@ +--- +title: A build ghost +date: 2023-12-20 +author: zombieJ +--- + +In the maintenance of antd-mobile, We meet an annoying ghost. It rarely appears when building locally, but it almost always appears in the github workflow. After a lot of tossing, We finally found its trace. + +### CI Failed...again + +For antd-mobile's CI, there is a task to check the build artifacts, which will prompt the file size changes. But in recent months, this task often fails to build, as shown in the following figure: + +![CI failed](https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*XSAESJ3_HWgAAAAAAAAAAAAADrJ8AQ/original) + +Check the log, we will get the error message of CSS file: + +![Unknown word](https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*2ybATYq9l2oAAAAAAAAAAAAADrJ8AQ/original) + +It seems that the error occurred when building 2x style (antd-mobile will generate 2x style for high-definition screen): + +```log +[09:44:16] Using gulpfile ~/work/ant-design-mobile/ant-design-mobile/gulpfile.js +[09:44:16] Starting 'default'... +[09:44:16] Starting 'clean'... +[09:44:17] Finished 'clean' after 286 ms +[09:44:17] Starting 'buildES'... +[09:44:26] Finished 'buildES' after 8.77 s +[09:44:26] Starting 'buildCJS'... +[09:44:27] Finished 'buildCJS' after 1.72 s +[09:44:27] Starting 'buildDeclaration'... +[09:44:27] Starting 'buildStyle'... +[09:44:28] Finished 'buildStyle' after 682 ms +[09:44:34] Finished 'buildDeclaration' after 6.5 s +[09:44:34] Starting 'copyAssets'... +[09:44:34] Finished 'copyAssets' after 2.37 ms +[09:44:34] Starting 'copyMetaFiles'... +[09:44:34] Finished 'copyMetaFiles' after 4.64 ms +[09:44:34] Starting 'generatePackageJSON'... +[09:44:34] Finished 'generatePackageJSON' after 2.72 ms +[09:44:34] Starting 'buildBundles'... +[09:44:45] Finished 'buildBundles' after 11 s +[09:44:45] Starting 'init2xFolder'... +[09:44:46] Finished 'init2xFolder' after 811 ms +[09:44:46] Starting 'build2xCSS'... +[09:44:46] 'build2xCSS' errored after 126 ms +[09:44:46] CssSyntaxError in plugin "gulp-postcss" +``` + +The `style.css` of `build2xCSS` comes from the artifact of `buildStyle`, so it can be determined that there is a problem in the `buildStyle` task. After checking the corresponding file `/lib/bundle/style.css`, we found the following content: + +![Break Lines](https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*5NqFR6_nkhwAAAAAAAAAAAAADrJ8AQ/original) + +The first line of `style.css` is the compressed style, and then the incomplete uncompressed style. Compared with the successful artifact, it will be found that the style after the second line is unexpected: + +![Success Style](https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*xnDRT5SDVvMAAAAAAAAAAAAADrJ8AQ/original) + +Check the uncompressed content, we will find that these contents already exist in the previous compressed content: + +![Duplicated Content](https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*wShGRJ16U1AAAAAAAAAAAAAADrJ8AQ/original) + +It is speculated that the uncompressed content was generated first during the build, and then the compressed operation was performed. But there is an asynchronous problem, the second task started to execute before the first task was completed, resulting in the duplication of content. What's even more bizarre is that if it is an asynchronous problem, the error file content generated on CI is surprisingly consistent. No matter how many times it is built, as long as it fails, it must be the same content. + +### Concurrent problem + +Check the `gulpfile.js` file, we found that `buildStyle` uses vite to build. Considering that it may be a problem with the build version, so we upgraded vite from `3.x` to `5.x`, but the problem still exists. So check the relevant configuration: + +```tsx +{ + root: process.cwd(), + mode: env, + logLevel: 'silent', + define: { 'process.env.NODE_ENV': `"${env}"` }, + build: { + cssTarget: 'chrome61', + lib: { + formats, + ... + }, + rollupOptions: { + output: { + dir: './lib/bundle', + globals: { + 'react': 'React', + 'react-dom': 'ReactDOM', + }, + }, + }, + minify: isProd ? 'esbuild' : false, + }, + } +``` + +Though closing the `logLevel: 'silent'` configuration, we can see more log content after rebuilding: + +![Bundle Result](https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*efjVR4DG_ysAAAAAAAAAAAAADrJ8AQ/original) + +We are close. When building, antd-mobile will create three copies of `es`, `cjs`, and `umd` through `lib.formats`. And each `format` will generate a `style.css` file. If it is just to overwrite the file, it should only waste extra build resources, and the compressed `style.css` will always be overwritten, and there should be no problem of simultaneous overwriting. Let's check the part that calls vite to build: + +```tsx +async function buildBundles(cb) { + const envs = ['development', 'production']; + const configs = envs.map((env) => + getViteConfigForPackage({ + env, + formats: ['es', 'cjs', 'umd'], + external: ['react', 'react-dom'], + }), + ); + + await Promise.all(configs.map((config) => vite.build(config))); + cb && cb(); +} +``` + +That's it. `Promise.all` is used to build concurrently, and vite's build is asynchronous. This causes a competition problem for `style.css`. The rollup called by vite will clean up the files and then perform write operations. Since the compressed style needs to be uglified, it is always slower than the uncompressed version. When rollup has finished cleaning and starts writing files, although the first part of the uncompressed version is deleted due to cleaning, the subsequent content is still written, while the compressed version starts writing from the beginning. When both are written, an error will occur and the content will be consistent under each CI build. The fix is also very simple, just change it to sequential execution: + +```tsx +for (const config of configs) { + await vite.build(config); +} +``` + +(Of course, subsequent optimizations are also needed for the script. Skip the unnecessary `style.css` generation) + +### That's all + +With the performance changes of github CI, the ghost that was originally difficult to encounter has become stable and reproducible, which is quite interesting. This also gives us the opportunity to locate the problem. diff --git a/docs/blog/build-ghost.zh-CN.md b/docs/blog/build-ghost.zh-CN.md new file mode 100644 index 0000000000..a6d06f4ef2 --- /dev/null +++ b/docs/blog/build-ghost.zh-CN.md @@ -0,0 +1,127 @@ +--- +title: 一个构建的幽灵 +date: 2023-12-20 +author: zombieJ +--- + +在 antd-mobile 的维护过程中,遇到了一个恼人的幽灵。它在本地构建时几乎不会出现,但是在 github 的 workflow 中,却几乎每次都会出现。在经过一番折腾后,终于找到了它的踪迹。 + +### CI 又挂了 + +在 antd-mobile 的 CI 中,有一个任务会对构建产物进行检查,会对文件大小变化进行提示。但是这个任务在最近几个月中,经常会出现构建失败的情况,如下图所示: + +![CI failed](https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*XSAESJ3_HWgAAAAAAAAAAAAADrJ8AQ/original) + +查看日志,会得到 CSS 文件报错的信息: + +![Unknown word](https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*2ybATYq9l2oAAAAAAAAAAAAADrJ8AQ/original) + +从构建流程看,似乎是在 2x 构建时报错(antd-mobile 会额外打一份 2x 的样式以适配高清屏): + +```log +[09:44:16] Using gulpfile ~/work/ant-design-mobile/ant-design-mobile/gulpfile.js +[09:44:16] Starting 'default'... +[09:44:16] Starting 'clean'... +[09:44:17] Finished 'clean' after 286 ms +[09:44:17] Starting 'buildES'... +[09:44:26] Finished 'buildES' after 8.77 s +[09:44:26] Starting 'buildCJS'... +[09:44:27] Finished 'buildCJS' after 1.72 s +[09:44:27] Starting 'buildDeclaration'... +[09:44:27] Starting 'buildStyle'... +[09:44:28] Finished 'buildStyle' after 682 ms +[09:44:34] Finished 'buildDeclaration' after 6.5 s +[09:44:34] Starting 'copyAssets'... +[09:44:34] Finished 'copyAssets' after 2.37 ms +[09:44:34] Starting 'copyMetaFiles'... +[09:44:34] Finished 'copyMetaFiles' after 4.64 ms +[09:44:34] Starting 'generatePackageJSON'... +[09:44:34] Finished 'generatePackageJSON' after 2.72 ms +[09:44:34] Starting 'buildBundles'... +[09:44:45] Finished 'buildBundles' after 11 s +[09:44:45] Starting 'init2xFolder'... +[09:44:46] Finished 'init2xFolder' after 811 ms +[09:44:46] Starting 'build2xCSS'... +[09:44:46] 'build2xCSS' errored after 126 ms +[09:44:46] CssSyntaxError in plugin "gulp-postcss" +``` + +而 `build2xCSS` 的 `style.css` 来源于 `buildStyle` 的产物,所以可以确定是 `buildStyle` 任务中出现了问题。在查看对应的文件 `/lib/bundle/style.css` 后,发现了如下的内容: + +![Break Lines](https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*5NqFR6_nkhwAAAAAAAAAAAAADrJ8AQ/original) + +`style.css` 第一行为压缩的样式,而后是不完整的未压缩的样式。对比成功的产物会发现第二行往后的样式是非预期的内容: + +![Success Style](https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*xnDRT5SDVvMAAAAAAAAAAAAADrJ8AQ/original) + +而根据未压缩的内容进行查询,会发现这些内容在之前的压缩内容中已经存在了: + +![Duplicated Content](https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*wShGRJ16U1AAAAAAAAAAAAAADrJ8AQ/original) + +因而猜测可能是构建时,先生成了未压缩的内容,然后又进行了压缩操作。但是又存在异步问题,第二个任务在第一个未完成时就开始执行了,导致了内容的重复。更诡异的是,如果是异步问题,CI 上生成的错误文件内容却出奇的一致。无论构建多少次,只要是失败的就必定是相同的内容。 + +### 并发问题 + +在查看了 `gulpfile.js` 文件后,发现 `buildStyle` 使用的是 vite 构建。考虑到可能是构建版本的问题,所以将 vite 的版本从 `3.x` 升级到了 `5.x`,但是问题依旧存在。于是又看了一下相关配置: + +```tsx +{ + root: process.cwd(), + mode: env, + logLevel: 'silent', + define: { 'process.env.NODE_ENV': `"${env}"` }, + build: { + cssTarget: 'chrome61', + lib: { + formats, + ... + }, + rollupOptions: { + output: { + dir: './lib/bundle', + globals: { + 'react': 'React', + 'react-dom': 'ReactDOM', + }, + }, + }, + minify: isProd ? 'esbuild' : false, + }, + } +``` + +通过关闭 `logLevel: 'silent'` 配置后再次构建,我们可以看到更多的日志内容: + +![Bundle Result](https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*efjVR4DG_ysAAAAAAAAAAAAADrJ8AQ/original) + +看来接近答案了,antd-mobile 在构建时会通过 `lib.formats` 创建 `es`、`cjs`、`umd` 三份副本。而每个 `format` 都会生成一次 `style.css` 文件。如果仅是不断覆盖文件,那应该只是额外的浪费了构建资源而已,最后总是会被压缩的 `style.css` 覆盖掉,不应该出现同时覆盖的问题。于是去看了一下调用 vite 构建的部分: + +```tsx +async function buildBundles(cb) { + const envs = ['development', 'production']; + const configs = envs.map((env) => + getViteConfigForPackage({ + env, + formats: ['es', 'cjs', 'umd'], + external: ['react', 'react-dom'], + }), + ); + + await Promise.all(configs.map((config) => vite.build(config))); + cb && cb(); +} +``` + +原来是使用了 `Promise.all` 来并发构建,而 vite 的构建是异步的。这使得 `style.css` 存在竞争问题。vite 调用的 rollup 会对文件进行清除,然后进行写操作。由于压缩样式需要进行 uglify,所以它总是慢于非压缩版本。当 rollup 都执行完清理操作开始写文件后,非压缩版本虽然前面一部分由于清理被删除但是后续内容仍然继续被写入,而压缩版本则从头开始写入。当两者都写入完毕后,就会出现错误并且内容却在每次 CI 构建下都一致的情况。修复也很简单,直接改成顺序执行即可: + +```tsx +for (const config of configs) { + await vite.build(config); +} +``` + +(当然,后续还需要对脚本进行优化。使其跳过非必要的 `style.css` 样式生成) + +### 以上 + +随着 github CI 的性能变化,原本很难遇到的幽灵反而变得可以稳定重现,颇为有趣。从而也使得我们有机会可以定位到问题之所在。 From eff720837cb5e5874ed50cbf300d004c4c2dea6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E7=88=B1=E5=90=83=E7=99=BD=E8=90=9D?= =?UTF-8?q?=E5=8D=9C?= Date: Thu, 21 Dec 2023 10:30:08 +0800 Subject: [PATCH 17/19] test: Update image snapshot logic (#46529) * test: mix snapshot * test: clean up * test: fix order * test: fix test logic * test: fix reset * test: refactor code * test: clean fetch * chore: lint * test: clean up * test: delay check * chore: refactor fetch * docs: update diff html * test: add ssr support * chore: part use ssr * chore: update style * chore: slice of it * docs: fix cut --- .jest.image.js | 4 +- .jest.js | 2 +- .jest.node.js | 2 +- components/carousel/__tests__/image.test.ts | 4 +- .../date-picker/__tests__/demo.test.tsx | 5 +- components/progress/__tests__/image.test.ts | 4 +- package.json | 2 +- scripts/visual-regression/build.ts | 39 +++---- .../visual-regression/report-template.html | 15 +++ tests/{setup.js => setup.ts} | 46 +++++--- tests/shared/imageTest.tsx | 101 +++++++++++++++++- tests/shared/rootPropsTest.tsx | 13 ++- tests/utils.tsx | 8 +- 13 files changed, 187 insertions(+), 58 deletions(-) rename tests/{setup.js => setup.ts} (51%) diff --git a/.jest.image.js b/.jest.image.js index fb42545326..78191c45d4 100644 --- a/.jest.image.js +++ b/.jest.image.js @@ -2,7 +2,7 @@ const { moduleNameMapper, transformIgnorePatterns } = require('./.jest'); // jest config for image snapshots module.exports = { - setupFiles: ['./tests/setup.js'], + setupFiles: ['./tests/setup.ts'], moduleFileExtensions: ['ts', 'tsx', 'js', 'md'], moduleNameMapper, transform: { @@ -19,5 +19,5 @@ module.exports = { }, }, preset: 'jest-puppeteer', - testTimeout: 10000, + testTimeout: 20000, }; diff --git a/.jest.js b/.jest.js index d71c4e8497..c3a1708cc4 100644 --- a/.jest.js +++ b/.jest.js @@ -32,7 +32,7 @@ function getTestRegex(libDir) { module.exports = { verbose: true, testEnvironment: 'jsdom', - setupFiles: ['./tests/setup.js', 'jest-canvas-mock'], + setupFiles: ['./tests/setup.ts', 'jest-canvas-mock'], setupFilesAfterEnv: ['./tests/setupAfterEnv.ts'], moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'md'], modulePathIgnorePatterns: ['/_site/'], diff --git a/.jest.node.js b/.jest.node.js index 54d6fb852d..e4631d406e 100644 --- a/.jest.node.js +++ b/.jest.node.js @@ -2,7 +2,7 @@ const { moduleNameMapper, transformIgnorePatterns } = require('./.jest'); // jest config for server render environment module.exports = { - setupFiles: ['./tests/setup.js'], + setupFiles: ['./tests/setup.ts'], setupFilesAfterEnv: ['./tests/setupAfterEnv.ts'], moduleFileExtensions: ['ts', 'tsx', 'js', 'md'], moduleNameMapper, diff --git a/components/carousel/__tests__/image.test.ts b/components/carousel/__tests__/image.test.ts index 30d204a801..4d1bdc6da2 100644 --- a/components/carousel/__tests__/image.test.ts +++ b/components/carousel/__tests__/image.test.ts @@ -1,5 +1,7 @@ import { imageDemoTest } from '../../../tests/shared/imageTest'; describe('Carousel image', () => { - imageDemoTest('carousel'); + imageDemoTest('carousel', { + ssr: true, + }); }); diff --git a/components/date-picker/__tests__/demo.test.tsx b/components/date-picker/__tests__/demo.test.tsx index 162c3a5a26..d8c4e237bb 100644 --- a/components/date-picker/__tests__/demo.test.tsx +++ b/components/date-picker/__tests__/demo.test.tsx @@ -1,5 +1,6 @@ -import dayjs from 'dayjs'; import * as React from 'react'; +import dayjs from 'dayjs'; + import demoTest, { rootPropsTest } from '../../../tests/shared/demoTest'; demoTest('date-picker', { skip: ['locale.tsx', 'component-token.tsx'], testRootProps: false }); @@ -10,7 +11,7 @@ rootPropsTest('date-picker', (DatePicker, props) => , { findRootElements: () => document.querySelectorAll('.ant-picker-range, .ant-picker-dropdown'), diff --git a/components/progress/__tests__/image.test.ts b/components/progress/__tests__/image.test.ts index ba763d18ec..e3298b732e 100644 --- a/components/progress/__tests__/image.test.ts +++ b/components/progress/__tests__/image.test.ts @@ -1,5 +1,7 @@ import { imageDemoTest } from '../../../tests/shared/imageTest'; describe('Progress image', () => { - imageDemoTest('progress'); + imageDemoTest('progress', { + ssr: true, + }); }); diff --git a/package.json b/package.json index aac032334c..b1db1c7a11 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "pretest": "npm run version && npm run component-changelog", "test": "jest --config .jest.js --no-cache", "test-all": "sh -e ./scripts/test-all.sh", - "test-image": "jest --config .jest.image.js --no-cache -i -u", + "test-image": "jest --config .jest.image.js --no-cache -i -u --forceExit", "test-node": "npm run version && jest --config .jest.node.js --no-cache", "test:update": "jest --config .jest.js --no-cache -u", "token-meta": "tsx scripts/generate-token-meta.ts", diff --git a/scripts/visual-regression/build.ts b/scripts/visual-regression/build.ts index 27e5842318..8bbdb75b52 100644 --- a/scripts/visual-regression/build.ts +++ b/scripts/visual-regression/build.ts @@ -1,23 +1,22 @@ /* eslint-disable compat/compat */ /* eslint-disable no-console, no-await-in-loop, import/no-extraneous-dependencies, lodash/import-scope, no-restricted-syntax */ -import path from 'path'; +import { assert } from 'console'; import fs from 'fs'; import os from 'os'; +import path from 'path'; import { Readable } from 'stream'; import { finished } from 'stream/promises'; - -import { remark } from 'remark'; -import remarkHtml from 'remark-html'; -import remarkGfm from 'remark-gfm'; -import minimist from 'minimist'; -import tar from 'tar'; -import fse from 'fs-extra'; import chalk from 'chalk'; +import fse from 'fs-extra'; import _ from 'lodash'; +import minimist from 'minimist'; import pixelmatch from 'pixelmatch'; import { PNG } from 'pngjs'; +import { remark } from 'remark'; +import remarkGfm from 'remark-gfm'; +import remarkHtml from 'remark-html'; import sharp from 'sharp'; -import { assert } from 'console'; +import tar from 'tar'; const ALI_OSS_BUCKET = 'antd-visual-diff'; @@ -158,10 +157,7 @@ function generateReport( const htmlReportLink = `${publicPath}/visualRegressionReport/report.html`; - const addonFullReportDesc = `\n\nToo many visual-regression diffs found, please check Full Report for details`; - - // github action pr comment has limit of 65536 4-byte unicode characters - const limit = 65536 - addonFullReportDesc.length; + const addonFullReportDesc = `\n\nCheck Full Report for details`; let reportMdStr = ` ${commonHeader} @@ -174,7 +170,7 @@ ${commonHeader} let fullVersionMd = reportMdStr; - let addonFullReportDescAdded = false; + let diffCount = 0; for (const badCase of badCases) { const { filename, type } = badCase; @@ -199,17 +195,16 @@ ${commonHeader} lineReportMdStr += ' |\n'; } - if (lineReportMdStr) { - if (reportMdStr.length + lineReportMdStr.length < limit) { - reportMdStr += lineReportMdStr; - } else if (!addonFullReportDescAdded) { - reportMdStr += addonFullReportDesc; - addonFullReportDescAdded = true; - } - fullVersionMd += lineReportMdStr; + diffCount += 1; + if (diffCount <= 10) { + reportMdStr += lineReportMdStr; } + + fullVersionMd += lineReportMdStr; } + reportMdStr += addonFullReportDesc; + // convert fullVersionMd to html return [reportMdStr, md2Html(fullVersionMd)]; } diff --git a/scripts/visual-regression/report-template.html b/scripts/visual-regression/report-template.html index dc5b178f3f..96c3f4aac7 100644 --- a/scripts/visual-regression/report-template.html +++ b/scripts/visual-regression/report-template.html @@ -16,6 +16,7 @@ table { width: 100%; border-collapse: collapse; + table-layout: fixed; } th, @@ -26,6 +27,20 @@ vertical-align: top; } + td img { + max-width: 100%; + } + + th, + td { + width: 10%; + } + + th+th, + td+td { + width: 30%; + } + th { background-color: #f2f2f2; } diff --git a/tests/setup.js b/tests/setup.ts similarity index 51% rename from tests/setup.js rename to tests/setup.ts index e5da82ca53..1977c6b1a8 100644 --- a/tests/setup.js +++ b/tests/setup.ts @@ -1,5 +1,9 @@ -/* eslint-disable no-console */ -const util = require('util'); +/* eslint-disable no-console, import/prefer-default-export */ +import util from 'util'; +import type { DOMWindow } from 'jsdom'; + +// import { fillWindowEnv } from './utils'; + const React = require('react'); // eslint-disable-next-line no-console @@ -20,17 +24,21 @@ console.error = (...args) => { } }; -/* eslint-disable global-require */ -if (typeof window !== 'undefined') { - global.window.resizeTo = (width, height) => { - global.window.innerWidth = width || global.window.innerWidth; - global.window.innerHeight = height || global.window.innerHeight; - global.window.dispatchEvent(new Event('resize')); +type Writeable = { -readonly [P in keyof T]: T[P] }; + +// This function can not move to external file since jest setup not support +export function fillWindowEnv(window: Window | DOMWindow) { + const win = window as Writeable & typeof globalThis; + + win.resizeTo = (width, height) => { + win.innerWidth = width || win.innerWidth; + win.innerHeight = height || win.innerHeight; + win.dispatchEvent(new Event('resize')); }; - global.window.scrollTo = () => {}; + win.scrollTo = () => {}; // ref: https://github.com/ant-design/ant-design/issues/18774 - if (!window.matchMedia) { - Object.defineProperty(global.window, 'matchMedia', { + if (!win.matchMedia) { + Object.defineProperty(win, 'matchMedia', { writable: true, configurable: true, value: jest.fn((query) => ({ @@ -44,11 +52,19 @@ if (typeof window !== 'undefined') { // Fix css-animation or rc-motion deps on these // https://github.com/react-component/motion/blob/9c04ef1a210a4f3246c9becba6e33ea945e00669/src/util/motion.ts#L27-L35 // https://github.com/yiminghe/css-animation/blob/a5986d73fd7dfce75665337f39b91483d63a4c8c/src/Event.js#L44 - window.AnimationEvent = window.AnimationEvent || window.Event; - window.TransitionEvent = window.TransitionEvent || window.Event; + win.AnimationEvent = win.AnimationEvent || win.Event; + win.TransitionEvent = win.TransitionEvent || win.Event; // ref: https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom // ref: https://github.com/jsdom/jsdom/issues/2524 - Object.defineProperty(window, 'TextEncoder', { writable: true, value: util.TextEncoder }); - Object.defineProperty(window, 'TextDecoder', { writable: true, value: util.TextDecoder }); + Object.defineProperty(win, 'TextEncoder', { writable: true, value: util.TextEncoder }); + Object.defineProperty(win, 'TextDecoder', { writable: true, value: util.TextDecoder }); } + +/* eslint-disable global-require */ +if (typeof window !== 'undefined') { + fillWindowEnv(window); +} + +global.requestAnimationFrame = global.requestAnimationFrame || global.setTimeout; +global.cancelAnimationFrame = global.cancelAnimationFrame || global.clearTimeout; diff --git a/tests/shared/imageTest.tsx b/tests/shared/imageTest.tsx index 9c104987bd..c6dfd6b136 100644 --- a/tests/shared/imageTest.tsx +++ b/tests/shared/imageTest.tsx @@ -1,15 +1,20 @@ +import path from 'path'; import React from 'react'; // Reference: https://github.com/ant-design/ant-design/pull/24003#discussion_r427267386 // eslint-disable-next-line import/no-unresolved import { createCache, extractStyle, StyleProvider } from '@ant-design/cssinjs'; import dayjs from 'dayjs'; -import path from 'path'; import { globSync } from 'glob'; import { configureToMatchImageSnapshot } from 'jest-image-snapshot'; +import { JSDOM } from 'jsdom'; import MockDate from 'mockdate'; import ReactDOMServer from 'react-dom/server'; import { App, ConfigProvider, theme } from '../../components'; +import { fillWindowEnv } from '../setup'; +import { render } from '../utils'; + +jest.mock('../../components/grid/hooks/useBreakpoint', () => () => ({})); const toMatchImageSnapshot = configureToMatchImageSnapshot({ customSnapshotsDir: `${process.cwd()}/imageSnapshots`, @@ -27,6 +32,7 @@ const themes = { interface ImageTestOptions { onlyViewport?: boolean; splitTheme?: boolean; + ssr?: boolean; } // eslint-disable-next-line jest/no-export @@ -35,6 +41,74 @@ export default function imageTest( identifier: string, options: ImageTestOptions, ) { + let doc: Document; + let container: HTMLDivElement; + + beforeAll(() => { + const dom = new JSDOM('

', { + url: 'http://localhost/', + }); + const win = dom.window; + doc = win.document; + + (global as any).window = win; + + // Fill env + const keys = [ + ...Object.keys(win), + 'HTMLElement', + 'SVGElement', + 'ShadowRoot', + 'Element', + 'File', + 'Blob', + ].filter((key) => !(global as any)[key]); + + keys.forEach((key) => { + (global as any)[key] = win[key]; + }); + + // Fake Resize Observer + global.ResizeObserver = function FakeResizeObserver() { + return { + observe() {}, + unobserve() {}, + disconnect() {}, + }; + } as any; + + // Fake promise not called + global.fetch = function mockFetch() { + return { + then() { + return this; + }, + catch() { + return this; + }, + finally() { + return this; + }, + }; + } as any; + + // Fake matchMedia + win.matchMedia = () => + ({ + matches: false, + addListener: jest.fn(), + removeListener: jest.fn(), + }) as any; + + // Fill window + fillWindowEnv(win); + }); + + beforeEach(() => { + doc.body.innerHTML = `
`; + container = doc.querySelector('#root')!; + }); + function test(name: string, suffix: string, themedComponent: React.ReactElement) { it(name, async () => { await jestPuppeteer.resetPage(); @@ -55,14 +129,30 @@ export default function imageTest( const cache = createCache(); + const emptyStyleHolder = doc.createElement('div'); + const element = ( - + {themedComponent} ); - const html = ReactDOMServer.renderToString(element); - const styleStr = extractStyle(cache); + let html: string; + let styleStr: string; + + if (options.ssr) { + html = ReactDOMServer.renderToString(element); + styleStr = extractStyle(cache); + } else { + const { unmount } = render(element, { + container, + }); + html = container.innerHTML; + styleStr = extractStyle(cache); + + // We should extract style before unmount + unmount(); + } await page.evaluate( (innerHTML, ssrStyle) => { @@ -141,6 +231,8 @@ type Options = { skip?: boolean | string[]; onlyViewport?: boolean | string[]; splitTheme?: boolean | string[]; + /** Use SSR render instead. Only used when the third part deps component */ + ssr?: boolean; }; // eslint-disable-next-line jest/no-export @@ -168,6 +260,7 @@ export function imageDemoTest(component: string, options: Options = {}) { splitTheme: options.splitTheme === true || (Array.isArray(options.splitTheme) && options.splitTheme.some((c) => file.endsWith(c))), + ssr: options.ssr, }); }); }); diff --git a/tests/shared/rootPropsTest.tsx b/tests/shared/rootPropsTest.tsx index 1f4ee413df..b38ce248c4 100644 --- a/tests/shared/rootPropsTest.tsx +++ b/tests/shared/rootPropsTest.tsx @@ -1,5 +1,6 @@ /* eslint-disable global-require, import/no-dynamic-require, jest/no-export */ import React from 'react'; + import ConfigProvider from '../../components/config-provider'; import { render, waitFakeTimer } from '../utils'; import { TriggerMockContext } from './demoTestContext'; @@ -20,14 +21,17 @@ function isSingleNode(node: any): node is Element { } export default function rootPropsTest( - component: string, + component: string | string[], customizeRender?: ( component: React.ComponentType & Record, props: any, ) => React.ReactNode, options?: Options, ) { - const Component = require(`../../components/${component}`).default as any; + const componentNames = Array.isArray(component) ? component : [component]; + const [componentName, subComponentName] = componentNames; + + const Component = require(`../../components/${componentName}`).default as any; const name = options?.name ? `(${options.name})` : ''; describe(`RootProps${name}`, () => { @@ -36,6 +40,7 @@ export default function rootPropsTest( beforeEach(() => { passed = false; jest.useFakeTimers(); + document.body.innerHTML = ''; }); afterEach(() => { @@ -46,7 +51,7 @@ export default function rootPropsTest( jest.useRealTimers(); }); - it('rootClassName', async () => { + it(['rootClassName', subComponentName].filter((v) => v).join(' '), async () => { const rootClassName = 'TEST_ROOT_CLS'; if (options?.beforeRender) { @@ -104,7 +109,7 @@ export default function rootPropsTest( expect(childList.length).toBeGreaterThan(0); if (options?.expectCount) { - expect(childList.length).toBe(options.expectCount); + expect(childList).toHaveLength(options.expectCount); } childList.forEach((ele) => { diff --git a/tests/utils.tsx b/tests/utils.tsx index d3427d79e3..3355faf802 100644 --- a/tests/utils.tsx +++ b/tests/utils.tsx @@ -1,10 +1,10 @@ +import type { ReactElement } from 'react'; +import React, { createRef, StrictMode } from 'react'; import type { RenderOptions } from '@testing-library/react'; import { act, render } from '@testing-library/react'; import MockDate from 'mockdate'; import { _rs as onEsResize } from 'rc-resize-observer/es/utils/observerUtil'; import { _rs as onLibResize } from 'rc-resize-observer/lib/utils/observerUtil'; -import type { ReactElement } from 'react'; -import React, { StrictMode } from 'react'; export function assertsExist(item?: T): asserts item is T { expect(item).not.toBeUndefined(); @@ -33,7 +33,7 @@ const customRender = (ui: ReactElement, options?: Omit render(ui, { wrapper: StrictMode, ...options }); export function renderHook(func: () => T): { result: React.RefObject } { - const result = React.createRef(); + const result = createRef(); const Demo: React.FC = () => { (result as any).current = func(); @@ -58,7 +58,7 @@ export { pureRender, customRender as render }; export const triggerResize = (target: Element) => { const originGetBoundingClientRect = target.getBoundingClientRect; - target.getBoundingClientRect = () => ({ width: 510, height: 903 } as DOMRect); + target.getBoundingClientRect = () => ({ width: 510, height: 903 }) as DOMRect; act(() => { onLibResize([{ target } as ResizeObserverEntry]); From 76f6ddc7e641de104fa3ff1e07574d2481e0bc28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E7=88=B1=E5=90=83=E7=99=BD=E8=90=9D?= =?UTF-8?q?=E5=8D=9C?= Date: Thu, 21 Dec 2023 14:39:43 +0800 Subject: [PATCH 18/19] fix: ColorPicker not support `prefixCls` (#46561) * fix: ColorPicker should support prefixCls * test: add test case --- components/color-picker/ColorPicker.tsx | 5 +- components/color-picker/util.ts | 2 - .../__snapshots__/components.test.tsx.snap | 105 ++++++++++++++++++ .../__tests__/components.test.tsx | 9 +- 4 files changed, 115 insertions(+), 6 deletions(-) diff --git a/components/color-picker/ColorPicker.tsx b/components/color-picker/ColorPicker.tsx index 708608f4d3..dbdaf8921b 100644 --- a/components/color-picker/ColorPicker.tsx +++ b/components/color-picker/ColorPicker.tsx @@ -12,8 +12,8 @@ import { getStatusClassNames } from '../_util/statusUtils'; import { devUseWarning } from '../_util/warning'; import type { ConfigConsumerProps } from '../config-provider/context'; import { ConfigContext } from '../config-provider/context'; -import useCSSVarCls from '../config-provider/hooks/useCSSVarCls'; import DisabledContext from '../config-provider/DisabledContext'; +import useCSSVarCls from '../config-provider/hooks/useCSSVarCls'; import useSize from '../config-provider/hooks/useSize'; import type { SizeType } from '../config-provider/SizeContext'; import { FormItemInputContext, NoFormStyle } from '../form/context'; @@ -33,7 +33,7 @@ import type { TriggerType, } from './interface'; import useStyle from './style'; -import { customizePrefixCls, genAlphaColor, generateColor, getAlphaColor } from './util'; +import { genAlphaColor, generateColor, getAlphaColor } from './util'; export type ColorPickerProps = Omit< RcColorPickerProps, @@ -92,6 +92,7 @@ const ColorPicker: CompoundedComponent = (props) => { className, size: customizeSize, rootClassName, + prefixCls: customizePrefixCls, styles, disabledAlpha = false, onFormatChange, diff --git a/components/color-picker/util.ts b/components/color-picker/util.ts index f67d9c0316..388658e572 100644 --- a/components/color-picker/util.ts +++ b/components/color-picker/util.ts @@ -2,8 +2,6 @@ import type { ColorGenInput } from '@rc-component/color-picker'; import type { Color } from './color'; import { ColorFactory } from './color'; -export const customizePrefixCls = 'ant-color-picker'; - export const generateColor = (color: ColorGenInput): Color => { if (color instanceof ColorFactory) { return color; diff --git a/components/config-provider/__tests__/__snapshots__/components.test.tsx.snap b/components/config-provider/__tests__/__snapshots__/components.test.tsx.snap index da945d5e35..88c876cf25 100644 --- a/components/config-provider/__tests__/__snapshots__/components.test.tsx.snap +++ b/components/config-provider/__tests__/__snapshots__/components.test.tsx.snap @@ -12543,6 +12543,111 @@ exports[`ConfigProvider components Collapse prefixCls 1`] = ` `; +exports[`ConfigProvider components ColorPicker configProvider 1`] = ` +
+
+
+
+
+`; + +exports[`ConfigProvider components ColorPicker configProvider componentDisabled 1`] = ` +
+
+
+
+
+`; + +exports[`ConfigProvider components ColorPicker configProvider componentSize large 1`] = ` +
+
+
+
+
+`; + +exports[`ConfigProvider components ColorPicker configProvider componentSize middle 1`] = ` +
+
+
+
+
+`; + +exports[`ConfigProvider components ColorPicker configProvider componentSize small 1`] = ` +
+
+
+
+
+`; + +exports[`ConfigProvider components ColorPicker normal 1`] = ` +
+
+
+
+
+`; + +exports[`ConfigProvider components ColorPicker prefixCls 1`] = ` +
+
+
+
+
+`; + exports[`ConfigProvider components DatePicker DatePicker configProvider 1`] = `
{ )); + // ColorPicker + testPair('ColorPicker', (props) => ); + // DatePicker describe('DatePicker', () => { testPair('DatePicker', (props) => ( From def84479aa1a0225d9369a2249a6de7fe2d70bae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Dec 2023 20:07:17 +0800 Subject: [PATCH 19/19] chore(deps-dev): bump eslint-plugin-unicorn from 49.0.0 to 50.0.1 (#46570) Bumps [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) from 49.0.0 to 50.0.1. - [Release notes](https://github.com/sindresorhus/eslint-plugin-unicorn/releases) - [Commits](https://github.com/sindresorhus/eslint-plugin-unicorn/compare/v49.0.0...v50.0.1) --- updated-dependencies: - dependency-name: eslint-plugin-unicorn dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b1db1c7a11..eaa22bb0d8 100644 --- a/package.json +++ b/package.json @@ -241,7 +241,7 @@ "eslint-plugin-markdown": "^3.0.1", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-unicorn": "^49.0.0", + "eslint-plugin-unicorn": "^50.0.1", "fast-glob": "^3.3.2", "fetch-jsonp": "^1.3.0", "fs-extra": "^11.1.1",