From 3409b0c5a06577b0495555517c08c85c15683d03 Mon Sep 17 00:00:00 2001 From: Christopher Kolstad Date: Thu, 25 May 2023 13:03:54 +0200 Subject: [PATCH] task: Add Unit test result check task (#3695) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After a Team Retro, one of our squads felt like we needed more data on our test suites. This is the first effort to make our test results easier to grab. It uses the test-reporter action to add a github check to our main build and PR builds with our test results. This at least should make it easier to parse which tests are failing. However, it does not give us trends. So it does not yet make it easier to decide which tests are flaky just from a quick view. --------- Co-authored-by: Gastón Fournier --- .github/workflows/build.yaml | 2 +- .github/workflows/build_prs.yaml | 1 - .github/workflows/build_prs_test_report.yaml | 45 ++++++++++++++++++ .github/workflows/pr_add_test_results.yaml | 16 +++++++ .gitignore | 1 + package.json | 12 +++++ .../__snapshots__/create-config.test.ts.snap | 1 + src/lib/app.ts | 2 +- src/lib/create-config.ts | 1 + src/lib/types/option.ts | 2 + src/lib/util/load-index-html.ts | 4 +- src/lib/util/rewriteHTML.test.ts | 3 +- src/lib/util/rewriteHTML.ts | 2 +- src/test/config/test-config.ts | 4 +- .../e2e/services/group-service.e2e.test.ts | 2 +- src/test/examples/favicon.ico | Bin 0 -> 15086 bytes src/test/examples/index.html | 26 ++++++++++ yarn.lock | 20 ++++++++ 18 files changed, 135 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/build_prs_test_report.yaml create mode 100644 .github/workflows/pr_add_test_results.yaml create mode 100644 src/test/examples/favicon.ico create mode 100644 src/test/examples/index.html diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 9360c7f72c..c23eaeedcc 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -41,7 +41,7 @@ jobs: - run: yarn - run: yarn build:frontend - run: yarn lint - - run: yarn run test + - run: yarn run test:report # This adds test results as github check to the workflow env: CI: true TEST_DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres diff --git a/.github/workflows/build_prs.yaml b/.github/workflows/build_prs.yaml index db002794e3..e5de6e48f8 100644 --- a/.github/workflows/build_prs.yaml +++ b/.github/workflows/build_prs.yaml @@ -20,4 +20,3 @@ jobs: - run: yarn install --frozen-lockfile --ignore-scripts - run: yarn lint - run: yarn build:backend - #- run: yarn build:frontend # not needed diff --git a/.github/workflows/build_prs_test_report.yaml b/.github/workflows/build_prs_test_report.yaml new file mode 100644 index 0000000000..58183b2455 --- /dev/null +++ b/.github/workflows/build_prs_test_report.yaml @@ -0,0 +1,45 @@ +name: TestReport +on: + pull_request: + paths-ignore: + - website/** + - coverage/** + +jobs: + testreport: + runs-on: ubuntu-latest + services: + # Label used to access the service container + postgres: + # Docker Hub image + image: postgres + # Provide the password for postgres + env: + POSTGRES_PASSWORD: postgres + # Set health checks to wait until postgres has started + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js 18 + uses: actions/setup-node@v3 + with: + node-version: 18 + cache: 'yarn' + - run: yarn install --frozen-lockfile --ignore-scripts + - run: yarn build:backend + - run: yarn test:report + env: + CI: true + TEST_DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres + DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres + - name: Upload test report to build # Done this way since external PRs would not be able to write the check. See https://github.com/marketplace/actions/test-reporter#recommended-setup-for-public-repositories + uses: actions/upload-artifact@v3 + if: success() || failure() + with: + name: test-results + path: ./reports/jest-junit.xml diff --git a/.github/workflows/pr_add_test_results.yaml b/.github/workflows/pr_add_test_results.yaml new file mode 100644 index 0000000000..1af8e5ac13 --- /dev/null +++ b/.github/workflows/pr_add_test_results.yaml @@ -0,0 +1,16 @@ +name: 'Attach Test report' +on: + workflow_run: + workflows: [TestReport] + types: + - completed +jobs: + report: + runs-on: ubuntu-latest + steps: + - uses: dorny/test-reporter@v1 + with: + artifact: test-results # artifact name + name: Unit Tests # Name of the check run which will be created + path: '*.xml' # Path to test results (inside artifact .zip) + reporter: jest-junit diff --git a/.gitignore b/.gitignore index 35d5da243b..c286b7318f 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,4 @@ frontend/build # Generated docs website/docs/reference/api/**/sidebar.js website/docs/generated +reports/jest-junit.xml diff --git a/package.json b/package.json index b7aca5a494..cbc9d84daf 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "test": "NODE_ENV=test PORT=4243 jest", "test:unit": "NODE_ENV=test PORT=4243 jest --testPathIgnorePatterns=src/test/e2e --testPathIgnorePatterns=dist", "test:docker": "./scripts/docker-postgres.sh", + "test:report": "NODE_ENV=test PORT=4243 jest --reporters=\"default\" --reporters=\"jest-junit\"", "test:docker:cleanup": "docker rm -f unleash-postgres", "test:watch": "yarn test --watch", "test:coverage": "NODE_ENV=test PORT=4243 jest --coverage --testLocationInResults --outputFile=\"coverage/report.json\" --forceExit --testTimeout=10000", @@ -61,6 +62,16 @@ "preversion": "./scripts/check-release.sh", "heroku-postbuild": "cd frontend && yarn && yarn build" }, + "jest-junit": { + "suiteName": "Unleash Unit Tests", + "outputDirectory": "./reports", + "outputName": "jest-junit.xml", + "uniqueOutputName": "false", + "classNameTemplate": "{classname}-{title}", + "titleTemplate": "{classname}-{title}", + "ancestorSeparator": " › ", + "usePathForSuiteName": "true" + }, "jest": { "automock": false, "maxWorkers": 4, @@ -193,6 +204,7 @@ "fetch-mock": "9.11.0", "husky": "8.0.3", "jest": "29.5.0", + "jest-junit": "^16.0.0", "lint-staged": "13.2.2", "nock": "13.3.1", "openapi-enforcer": "1.22.3", diff --git a/src/lib/__snapshots__/create-config.test.ts.snap b/src/lib/__snapshots__/create-config.test.ts.snap index 03bcaee127..22c257eae2 100644 --- a/src/lib/__snapshots__/create-config.test.ts.snap +++ b/src/lib/__snapshots__/create-config.test.ts.snap @@ -149,6 +149,7 @@ exports[`should create default config 1`] = ` "preHook": undefined, "preRouterHook": undefined, "prometheusApi": undefined, + "publicFolder": undefined, "secureHeaders": false, "segmentValuesLimit": 1000, "server": { diff --git a/src/lib/app.ts b/src/lib/app.ts index 662ccf57f2..32db3d0266 100644 --- a/src/lib/app.ts +++ b/src/lib/app.ts @@ -40,7 +40,7 @@ export default async function getApp( const app = express(); const baseUriPath = config.server.baseUriPath || ''; - const publicFolder = findPublicFolder(); + const publicFolder = config.publicFolder || findPublicFolder(); let indexHTML = await loadIndexHTML(config, publicFolder); app.set('trust proxy', true); diff --git a/src/lib/create-config.ts b/src/lib/create-config.ts index 0aacf5efe3..d07a0615fb 100644 --- a/src/lib/create-config.ts +++ b/src/lib/create-config.ts @@ -497,6 +497,7 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig { clientFeatureCaching, accessControlMaxAge, prometheusApi, + publicFolder: options.publicFolder, }; } diff --git a/src/lib/types/option.ts b/src/lib/types/option.ts index bd25be6414..644a3e8d7f 100644 --- a/src/lib/types/option.ts +++ b/src/lib/types/option.ts @@ -116,6 +116,7 @@ export interface IUnleashOptions { flagResolver?: IFlagResolver; accessControlMaxAge?: number; prometheusApi?: string; + publicFolder?: string; } export interface IEmailOption { @@ -203,4 +204,5 @@ export interface IUnleashConfig { clientFeatureCaching: IClientCachingOption; accessControlMaxAge: number; prometheusApi?: string; + publicFolder?: string; } diff --git a/src/lib/util/load-index-html.ts b/src/lib/util/load-index-html.ts index 9f732c379a..865162af0e 100644 --- a/src/lib/util/load-index-html.ts +++ b/src/lib/util/load-index-html.ts @@ -17,7 +17,9 @@ export async function loadIndexHTML( indexHTML = await res.text(); } else { indexHTML = fs - .readFileSync(path.join(publicFolder, 'index.html')) + .readFileSync( + path.join(config.publicFolder || publicFolder, 'index.html'), + ) .toString(); } diff --git a/src/lib/util/rewriteHTML.test.ts b/src/lib/util/rewriteHTML.test.ts index b40f30ce6c..172e3c0020 100644 --- a/src/lib/util/rewriteHTML.test.ts +++ b/src/lib/util/rewriteHTML.test.ts @@ -1,10 +1,9 @@ import fs from 'fs'; import path from 'path'; import { rewriteHTML } from './rewriteHTML'; -import { findPublicFolder } from './findPublicFolder'; const input = fs - .readFileSync(path.join(findPublicFolder(), 'index.html')) + .readFileSync(path.join(__dirname, '../../test/examples', 'index.html')) .toString(); test('rewriteHTML substitutes meta tag with existing rewrite value', () => { diff --git a/src/lib/util/rewriteHTML.ts b/src/lib/util/rewriteHTML.ts index 6f05dd1e14..58de0c11c4 100644 --- a/src/lib/util/rewriteHTML.ts +++ b/src/lib/util/rewriteHTML.ts @@ -11,7 +11,7 @@ export const rewriteHTML = ( const faviconPrefix = cdnPrefix ? 'https://cdn.getunleash.io' : ''; result = result.replace(/::faviconPrefix::/gi, faviconPrefix); - result = result.replace(/::uiFlags::/gi, uiFlags); + result = result.replace(/::uiFlags::/gi, uiFlags || '{}'); result = result.replace( /\/static/gi, diff --git a/src/test/config/test-config.ts b/src/test/config/test-config.ts index 20a83507a0..ccf9bd9b12 100644 --- a/src/test/config/test-config.ts +++ b/src/test/config/test-config.ts @@ -6,6 +6,7 @@ import { } from '../../lib/types/option'; import getLogger from '../fixtures/no-logger'; import { createConfig } from '../../lib/create-config'; +import path from 'path'; function mergeAll(objects: Partial[]): T { return merge.all(objects.filter((i) => i)); @@ -28,7 +29,8 @@ export function createTestConfig(config?: IUnleashOptions): IUnleashConfig { embedProxyFrontend: true, }, }, + publicFolder: path.join(__dirname, '../examples'), }; - const options = mergeAll([testConfig, config]); + const options = mergeAll([testConfig, config || {}]); return createConfig(options); } diff --git a/src/test/e2e/services/group-service.e2e.test.ts b/src/test/e2e/services/group-service.e2e.test.ts index 5048df20da..9c4d1e4332 100644 --- a/src/test/e2e/services/group-service.e2e.test.ts +++ b/src/test/e2e/services/group-service.e2e.test.ts @@ -104,7 +104,7 @@ test('adding a root role to a group with a project role should fail', async () = description: 'root_group', }); - stores.accessStore.addGroupToRole(group.id, 1, 'test', 'default'); + await stores.accessStore.addGroupToRole(group.id, 1, 'test', 'default'); await expect(() => { return groupService.updateGroup( diff --git a/src/test/examples/favicon.ico b/src/test/examples/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..551d158eee9678935e6b26ecb07611fe1b186ac8 GIT binary patch literal 15086 zcmdU0TZ|M%6s>VpetaN`Fx>;YDi{qvBqY8-x@RBk^uQ7mvl^ojBM9Q-$A#S$G>$)L ze6I09{7_>2&_wx=l@%0{{SZNdCV&thK*mR+@r$?wH`$f;oSv?xcc!27rjy$0sj7SL zsav;h-@aWdL_)NPg$o7hHu3R%A#M>uw6)p4rwefkZPQV+|Iv$u*n$B!VGKybLnv&w zu6c#37JpYRzUJ~wTJ112b-kghLs?zfX6VUJSPJ**>sDX8+OF#}FRKNHxIBR~mC=d!xFvq8 z<~lE5GWV(yKrtG+?`%!N#t+vUyCY9ijxAfN%!vWn8A`tZK6!_izs*k3TMfqNSG1>8 z2Uvs~%Vse58el1NuIkYkwv+(w9nFK?ex_*2olt$~o(66_QzAcy%G77s{OOl`uWmgx z57_JBBg>ul*`VhGVu3H3Sod^+^W=Gs+S?DEK63(d9J1)ilRos#%M z>*ejr9mR7nus@>WC-!o#qq)uIxlPY|7S1cGe2m-S#!vr>w#lgU4abj|&;498(#cIx zv2$F*@fZB#fLsG$I&cBv|C;#u-URG%-aVQ{{}YBW5QX$j%^bAF%7(n0?!lG z#Q(?dC(Yd>A90O;rcIn zf3emeMvk-L_>sGpx|g+`(~lHG1--xDf46@e$v)2AtB|MHUh`~AD~ly=cMTib?K!@g z@>zvEoEx@tzhY@>KJYhl{%Sniq2A~K_PBvBeY$Da0N+qNAWvz^32{+#+L1a!Y*WDc z{OIUVuf`f2Z<=*LE}uDlAGn^)%nxB5erSLX5L+Jzs+y41~zDo_4+-Ht!@@#kE zmGdZ`pPaYU15{$^#nDsV)|=F$)T`99t#_W&YD3XcoO4>!@uPxk+0t3p!B*D5X5O~; zdEtB$&N!(f*!ypxtmc>sM3j*B_Aa;-KHy=0QEl?+4AIMT;&eVHl$Ueyj)c zJrz}M$v90tnbp-5F+^HJdwWF-c)eJ{FXH@5=rr|RT^BgP7k<%S@EKjgqg>ez9i9sz z{w2rfc`eUzA>N^G{j^}`9V6LT1^Ri}OTMAaHY(s53v;neQtzPpvnPJ^7eZcCNlRSSRogavd=D?}Fr0cGz`duz$+;e_{#ZNgqY| z_Su%ev9*v-Z1mNLRn`XKWM8f1^H~Dl{!U!^WB;5s4}ZUJN;&ZCMw4qG3+*9{FZ$m^ z*%dafc>a`KOv5(!MVjIu?X$*>mfv9gC$~0C|5nVDT-PZ1+<$g% zvLW^-&&OtxMGrGDeXbp;=Kc8)XuS8#L<35#zG(kKW(@ObvyjQn;5@TA% z)lxp|Ogfbf#2ezHV$mY5cFUIci1A~8vyLSfbI54PSEan-n(I*O_%kdHXN-(Fh5E$U z^JYvR5`Rm5H1hpJVqk6CWF`CJ2;*uu&$#zF#Kx9?2#FDk*5eRqNE=sP(0KaljLzpp za;yE0wjXl$Tlb8k5X;5Q^O@tVra9W;q-c@i+a&$un1ui+iri&+ax!Pg>c|dtU65ZFbG|{l(oDi(XTH0<92d1 zI%lrD=e)SKE?Hw)edcW1A=(C9?d~zY_mu6j;Y6HsZM1c_{n~u^e=x-1*rErfGqg7k wS_g`)j{(GfdqFSv?;g^z&lzanOd=P28hPJQ=2lU1*qJQFmu#2gNJHBH0Vj5x6951J literal 0 HcmV?d00001 diff --git a/src/test/examples/index.html b/src/test/examples/index.html new file mode 100644 index 0000000000..e3c7d02cda --- /dev/null +++ b/src/test/examples/index.html @@ -0,0 +1,26 @@ + + + + + + + + + + + + Unleash + + + + + + + +
+ + + diff --git a/yarn.lock b/yarn.lock index 17a4d57ee1..0244c0dd80 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4466,6 +4466,16 @@ jest-haste-map@^29.5.0: optionalDependencies: fsevents "^2.3.2" +jest-junit@^16.0.0: + version "16.0.0" + resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-16.0.0.tgz#d838e8c561cf9fdd7eb54f63020777eee4136785" + integrity sha512-A94mmw6NfJab4Fg/BlvVOUXzXgF0XIH6EmTgJ5NDPp4xoKq0Kr7sErb+4Xs9nZvu58pJojz5RFGpqnZYJTrRfQ== + dependencies: + mkdirp "^1.0.4" + strip-ansi "^6.0.1" + uuid "^8.3.2" + xml "^1.0.1" + jest-leak-detector@^29.5.0: version "29.5.0" resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz#cf4bdea9615c72bac4a3a7ba7e7930f9c0610c8c" @@ -7322,6 +7332,11 @@ uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + uuid@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" @@ -7485,6 +7500,11 @@ write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" +xml@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" + integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== + xtend@^4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"