From 3bd4986905593505b1190aff62f3617b7906be30 Mon Sep 17 00:00:00 2001 From: jekabskarklins Date: Tue, 23 Sep 2025 19:54:19 +0200 Subject: [PATCH 1/8] fix: add count_self_hosted_runners job to optimize e2e testing based on available runners --- .github/workflows/test-build.yml | 45 +++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index db182f9a78..d7d5a690c2 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -256,35 +256,74 @@ jobs: REPO_DIR_NAME=$(basename $GITHUB_WORKSPACE) npm run test:backend - e2e: + + count_self_hosted_runners: runs-on: ubuntu-latest - needs: [resolve_dep, build] + outputs: + idle: ${{ steps.get.outputs.idle }} + steps: + - name: Get idle runner count + id: get + env: + OWNER: ${{ github.repository_owner }} + AUTH: ${{ secrets.GH_API_TOKEN }} + run: | + set -euo pipefail + REPO="${GITHUB_REPOSITORY#*/}" + + RESPONSE="$( + curl -sS --fail \ + -H "Authorization: Bearer $AUTH" \ + "https://api.github.com/repos/$OWNER/$REPO/actions/runners?per_page=100" + )" + + IDLE="$(echo "$RESPONSE" | jq ' + [ (.runners // [])[]? + | select(.status == "online" and (.busy | not)) + | select([.labels[]?.name] | index("self-hosted") and index("Linux") and index("X64")) + ] | length + ')" + echo "idle=$IDLE" >> "$GITHUB_OUTPUT" + + e2e: + needs: [resolve_dep, build, count_self_hosted_runners] strategy: fail-fast: false matrix: pattern: - id: ae + idx: 0 files: cypress/e2e/[a-e]*.ts - id: fh + idx: 1 files: cypress/e2e/[f-h]*.ts - id: io + idx: 2 files: cypress/e2e/[i-o]*.ts - id: p-am + idx: 3 files: cypress/e2e/p[a-m]*.ts - id: p-nz + idx: 4 files: cypress/e2e/p[n-z]*.ts - id: rs + idx: 5 files: cypress/e2e/[r-s]*.ts - id: t + idx: 6 files: cypress/e2e/t!(emplateDeleteAndArchive).ts - id: templateDelete + idx: 7 files: cypress/e2e/templateDeleteAndArchive*.ts - id: uz + idx: 8 files: cypress/e2e/[u-z]*.ts - id: AZ + idx: 9 files: cypress/e2e/[A-Z]*.ts - + runs-on: ${{ matrix.pattern.idx < needs.count_self_hosted_runners.outputs.idle && 'self-hosted' || 'ubuntu-latest' }} + steps: - uses: actions/checkout@v4 From d9b08ec5173043ea1a6a12e847745ae255cd1831 Mon Sep 17 00:00:00 2001 From: jekabskarklins Date: Tue, 23 Sep 2025 20:10:11 +0200 Subject: [PATCH 2/8] fix: ensure count_self_hosted_runners job depends on build for proper execution order --- .github/workflows/test-build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index d7d5a690c2..5263ffd48c 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -258,6 +258,7 @@ jobs: npm run test:backend count_self_hosted_runners: + needs: build runs-on: ubuntu-latest outputs: idle: ${{ steps.get.outputs.idle }} @@ -392,6 +393,7 @@ jobs: - name: Download required repositories run: | cd "$GITHUB_WORKSPACE/.." + rm -rf user-office-factory git clone --depth 1 --branch "${{ needs.resolve_dep.outputs.FACTORY_TAG }}" https://github.com/UserOfficeProject/user-office-factory.git - name: Run e2e tests stfc From 40e32c5e3d046bba31f035774ae878172970c822 Mon Sep 17 00:00:00 2001 From: jekabskarklins Date: Wed, 24 Sep 2025 07:50:33 +0200 Subject: [PATCH 3/8] fix: update cypress run action to use electron browser for consistency --- apps/e2e/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/e2e/package.json b/apps/e2e/package.json index 7ab1f5b945..a244586dc6 100644 --- a/apps/e2e/package.json +++ b/apps/e2e/package.json @@ -45,6 +45,6 @@ "lint:fix": "tsc --noEmit && eslint . --ext .js,.ts --quiet --fix", "cy:open": "cypress open --e2e", "cy:run": "cypress run --e2e", - "cy:run:action": "cypress run --spec \"${CYPRES_SPEC_PATTERN}\" --browser chrome --e2e" + "cy:run:action": "cypress run --spec \"${CYPRES_SPEC_PATTERN}\" --browser electron --e2e" } } From 00e5eec2db2870176fc6c99ff987155d7831b448 Mon Sep 17 00:00:00 2001 From: jekabskarklins Date: Thu, 25 Sep 2025 17:01:26 +0200 Subject: [PATCH 4/8] fix: remove redundant updateCall calls in Calls tests for cleaner code --- apps/e2e/cypress/e2e/calls.cy.ts | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/apps/e2e/cypress/e2e/calls.cy.ts b/apps/e2e/cypress/e2e/calls.cy.ts index 67fb2e5ed6..5add126092 100644 --- a/apps/e2e/cypress/e2e/calls.cy.ts +++ b/apps/e2e/cypress/e2e/calls.cy.ts @@ -1064,20 +1064,6 @@ context('Calls tests', () => { .contains('7 hours remaining'); }); - cy.updateCall({ - id: initialDBData.call.id, - ...newCall, - shortCode: initialDBData.call.shortCode, - endCall: DateTime.now().plus({ minutes: 1, seconds: 50 }), - proposalWorkflowId: initialDBData.proposal.id, - }).then(() => { - cy.reload(); - - cy.contains(initialDBData.call.shortCode) - .parent() - .contains('1 minute remaining'); - }); - cy.updateCall({ id: initialDBData.call.id, ...newCall, @@ -1176,21 +1162,6 @@ context('Calls tests', () => { .contains('7 hours remaining'); }); - cy.updateCall({ - id: initialDBData.call.id, - ...newCall, - shortCode: initialDBData.call.shortCode, - endCall: yesterday, - endCallInternal: DateTime.now().plus({ minutes: 1, seconds: 30 }), - proposalWorkflowId: initialDBData.proposal.id, - }).then(() => { - cy.reload(); - - cy.contains(initialDBData.call.shortCode) - .parent() - .contains('1 minute remaining'); - }); - cy.updateCall({ id: initialDBData.call.id, ...newCall, From edb530fa4b7ee655bed7451ba04b3c28c1919daa Mon Sep 17 00:00:00 2001 From: jekabskarklins Date: Thu, 25 Sep 2025 17:35:48 +0200 Subject: [PATCH 5/8] fix: rename idx to order for clarity in e2e test matrix and update runner selection logic --- .github/workflows/test-build.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 5263ffd48c..1b113a0aa3 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -294,36 +294,36 @@ jobs: matrix: pattern: - id: ae - idx: 0 + order: 0 files: cypress/e2e/[a-e]*.ts - id: fh - idx: 1 + order: 1 files: cypress/e2e/[f-h]*.ts - id: io - idx: 2 + order: 2 files: cypress/e2e/[i-o]*.ts - id: p-am - idx: 3 + order: 3 files: cypress/e2e/p[a-m]*.ts - id: p-nz - idx: 4 + order: 4 files: cypress/e2e/p[n-z]*.ts - id: rs - idx: 5 + order: 5 files: cypress/e2e/[r-s]*.ts - id: t - idx: 6 + order: 6 files: cypress/e2e/t!(emplateDeleteAndArchive).ts - id: templateDelete - idx: 7 + order: 7 files: cypress/e2e/templateDeleteAndArchive*.ts - id: uz - idx: 8 + order: 8 files: cypress/e2e/[u-z]*.ts - id: AZ - idx: 9 + order: 9 files: cypress/e2e/[A-Z]*.ts - runs-on: ${{ matrix.pattern.idx < needs.count_self_hosted_runners.outputs.idle && 'self-hosted' || 'ubuntu-latest' }} + runs-on: ${{ matrix.pattern.order < needs.count_self_hosted_runners.outputs.idle && 'self-hosted' || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 From 559de0debe4e34a1b2fe3e374858ea76fa8ed370 Mon Sep 17 00:00:00 2001 From: jekabskarklins Date: Thu, 25 Sep 2025 17:46:10 +0200 Subject: [PATCH 6/8] fix: remove redundant logout call in PageTable component tests for cleaner code --- apps/e2e/cypress/e2e/peopleTable.cy.ts | 2 -- apps/e2e/cypress/support/user.ts | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/e2e/cypress/e2e/peopleTable.cy.ts b/apps/e2e/cypress/e2e/peopleTable.cy.ts index 20b1ab6826..c882e0a42b 100644 --- a/apps/e2e/cypress/e2e/peopleTable.cy.ts +++ b/apps/e2e/cypress/e2e/peopleTable.cy.ts @@ -257,8 +257,6 @@ context('PageTable component tests', () => { cy.get('@modal').find('tr[index="0"] input:checked'); cy.get('@modal').contains('1 user(s) selected'); cy.get('[data-cy="assign-selected-users"]').click(); - - cy.logout(); }); }); diff --git a/apps/e2e/cypress/support/user.ts b/apps/e2e/cypress/support/user.ts index 583c884694..20c023542d 100644 --- a/apps/e2e/cypress/support/user.ts +++ b/apps/e2e/cypress/support/user.ts @@ -209,7 +209,7 @@ const logout = () => { localStorage.removeItem('expToken'); localStorage.removeItem('impersonatingUserId'); - cy.visit('/'); + cy.visit(Cypress.config('baseUrl') || '/'); }; const createUserByEmailInvite = ( From 4a924ba7d7c7e23e9bc4eac4cc3daec7f4625664 Mon Sep 17 00:00:00 2001 From: jekabskarklins Date: Thu, 25 Sep 2025 20:11:44 +0200 Subject: [PATCH 7/8] fix: update technique and instrument names to use lorem.word for better consistency --- apps/e2e/cypress/e2e/techniqueProposals.cy.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/e2e/cypress/e2e/techniqueProposals.cy.ts b/apps/e2e/cypress/e2e/techniqueProposals.cy.ts index 2be1bdd313..b3634b72bb 100644 --- a/apps/e2e/cypress/e2e/techniqueProposals.cy.ts +++ b/apps/e2e/cypress/e2e/techniqueProposals.cy.ts @@ -139,31 +139,31 @@ context('Technique Proposal tests', () => { }; const technique1 = { - name: faker.word.words(1), + name: faker.lorem.word({ length: 10 }), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), }; const technique2 = { - name: faker.word.words(1), + name: faker.lorem.word({ length: 10 }), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), }; const technique3 = { - name: faker.word.words(1), + name: faker.lorem.word({ length: 10 }), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), }; const technique4 = { - name: faker.word.words(1), + name: faker.lorem.word({ length: 10 }), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), }; const technique5 = { - name: faker.word.words(1), + name: faker.lorem.word({ length: 10 }), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), }; @@ -174,35 +174,35 @@ context('Technique Proposal tests', () => { const scientist4 = initialDBData.users.placeholderUser; const instrument1 = { - name: faker.word.words(1), + name: faker.lorem.word({ length: 10 }), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), managerUserId: scientist1.id, }; const instrument2 = { - name: faker.word.words(1), + name: faker.lorem.word({ length: 10 }), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), managerUserId: scientist2.id, }; const instrument3 = { - name: faker.word.words(1), + name: faker.lorem.word({ length: 10 }), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), managerUserId: scientist3.id, }; const instrument4 = { - name: faker.word.words(1), + name: faker.lorem.word({ length: 10 }), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), managerUserId: scientist4.id, }; const instrument5 = { - name: faker.word.words(1), + name: faker.lorem.word({ length: 10 }), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), managerUserId: scientist2.id, From 1bb3dce11bd0f91c5a4f38ae292bece0906c31fe Mon Sep 17 00:00:00 2001 From: jekabskarklins Date: Fri, 3 Oct 2025 11:19:16 +0200 Subject: [PATCH 8/8] fix: revert back changes --- apps/e2e/cypress/e2e/techniqueProposals.cy.ts | 20 +++++++++---------- apps/e2e/cypress/support/user.ts | 2 +- apps/e2e/package.json | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/e2e/cypress/e2e/techniqueProposals.cy.ts b/apps/e2e/cypress/e2e/techniqueProposals.cy.ts index ee17c9721a..7c8833b923 100644 --- a/apps/e2e/cypress/e2e/techniqueProposals.cy.ts +++ b/apps/e2e/cypress/e2e/techniqueProposals.cy.ts @@ -140,31 +140,31 @@ context('Technique Proposal tests', () => { }; const technique1 = { - name: faker.lorem.word({ length: 10 }), + name: faker.word.words(1), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), }; const technique2 = { - name: faker.lorem.word({ length: 10 }), + name: faker.word.words(1), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), }; const technique3 = { - name: faker.lorem.word({ length: 10 }), + name: faker.word.words(1), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), }; const technique4 = { - name: faker.lorem.word({ length: 10 }), + name: faker.word.words(1), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), }; const technique5 = { - name: faker.lorem.word({ length: 10 }), + name: faker.word.words(1), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), }; @@ -175,35 +175,35 @@ context('Technique Proposal tests', () => { const scientist4 = initialDBData.users.placeholderUser; const instrument1 = { - name: faker.lorem.word({ length: 10 }), + name: faker.word.words(1), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), managerUserId: scientist1.id, }; const instrument2 = { - name: faker.lorem.word({ length: 10 }), + name: faker.word.words(1), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), managerUserId: scientist2.id, }; const instrument3 = { - name: faker.lorem.word({ length: 10 }), + name: faker.word.words(1), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), managerUserId: scientist3.id, }; const instrument4 = { - name: faker.lorem.word({ length: 10 }), + name: faker.word.words(1), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), managerUserId: scientist4.id, }; const instrument5 = { - name: faker.lorem.word({ length: 10 }), + name: faker.word.words(1), shortCode: faker.string.alphanumeric(15), description: faker.word.words(5), managerUserId: scientist2.id, diff --git a/apps/e2e/cypress/support/user.ts b/apps/e2e/cypress/support/user.ts index 20c023542d..583c884694 100644 --- a/apps/e2e/cypress/support/user.ts +++ b/apps/e2e/cypress/support/user.ts @@ -209,7 +209,7 @@ const logout = () => { localStorage.removeItem('expToken'); localStorage.removeItem('impersonatingUserId'); - cy.visit(Cypress.config('baseUrl') || '/'); + cy.visit('/'); }; const createUserByEmailInvite = ( diff --git a/apps/e2e/package.json b/apps/e2e/package.json index a244586dc6..7ab1f5b945 100644 --- a/apps/e2e/package.json +++ b/apps/e2e/package.json @@ -45,6 +45,6 @@ "lint:fix": "tsc --noEmit && eslint . --ext .js,.ts --quiet --fix", "cy:open": "cypress open --e2e", "cy:run": "cypress run --e2e", - "cy:run:action": "cypress run --spec \"${CYPRES_SPEC_PATTERN}\" --browser electron --e2e" + "cy:run:action": "cypress run --spec \"${CYPRES_SPEC_PATTERN}\" --browser chrome --e2e" } }