From 8b5cbcb541b1f5addaa2759cb8f08bac85ceac4f Mon Sep 17 00:00:00 2001 From: rtibblesbot Date: Wed, 30 Sep 2026 17:10:56 +0000 Subject: [PATCH 1/2] verify: annotate jest failures --- .github/annot.js | 10 ++++++++++ .github/workflows/frontendtest.yml | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 .github/annot.js diff --git a/.github/annot.js b/.github/annot.js new file mode 100644 index 0000000000..d16e949a49 --- /dev/null +++ b/.github/annot.js @@ -0,0 +1,10 @@ +const r = require('../r.json'); +let n = 0; +for (const f of r.testResults) for (const t of f.assertionResults) if (t.status === 'failed') { + const m = (t.fullName + ' :: ' + t.failureMessages.join(' ')).replace(/\u001b\[[0-9;]*m/g, '').replace(/[\r\n]+/g, ' | ').slice(0, 1500); + console.log(`::error title=${f.name.split('/').pop()}::${m}`); + n++; +} +for (const f of r.testResults) if (f.status === 'failed' && !f.assertionResults.some(t => t.status === 'failed')) + console.log(`::error title=SUITE ${f.name.split('/').pop()}::${(f.message||'').replace(/\u001b\[[0-9;]*m/g,'').replace(/[\r\n]+/g,' | ').slice(0,1500)}`); +console.log('failed', n); diff --git a/.github/workflows/frontendtest.yml b/.github/workflows/frontendtest.yml index c3eb5e9db0..03789fa9f8 100644 --- a/.github/workflows/frontendtest.yml +++ b/.github/workflows/frontendtest.yml @@ -51,4 +51,6 @@ jobs: pnpm install --frozen-lockfile pnpm rebuild node-sass - name: Run tests - run: pnpm run test + run: | + pnpm run test contentcuration/contentcuration/frontend/shared/views/QTIEditor contentcuration/contentcuration/frontend/shared/utils contentcuration/contentcuration/frontend/channelEdit/vuex/assessmentItem --json --outputFile=r.json || true + node .github/annot.js From 2e9cd7a98a7c028072debfe27d1d9d8e1b582e7d Mon Sep 17 00:00:00 2001 From: rtibblesbot Date: Wed, 30 Sep 2026 17:13:17 +0000 Subject: [PATCH 2/2] verify: fix --- .../__tests__/InteractionSection.spec.js | 5 ++++- .../QTIItemEditor/__tests__/QTIItemEditor.spec.js | 7 +++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/InteractionSection/__tests__/InteractionSection.spec.js b/contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/InteractionSection/__tests__/InteractionSection.spec.js index 0d2e88a8ff..71643822a7 100644 --- a/contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/InteractionSection/__tests__/InteractionSection.spec.js +++ b/contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/InteractionSection/__tests__/InteractionSection.spec.js @@ -27,6 +27,9 @@ const renderSection = (props = {}) => routes: new VueRouter(), }); +// jest_config/setup.js adds a hidden csrf input to the document. +const isAuthorInput = el => el.name !== 'csrfmiddlewaretoken'; + describe('InteractionSection', () => { describe('choice interaction', () => { it('renders the prompt from the XML via ChoiceInteractionEditor', () => { @@ -145,7 +148,7 @@ describe('InteractionSection', () => { it('renders nothing editable', () => { renderSection({ interaction: interactionBlock(UNKNOWN_INTERACTION_XML), mode: 'edit' }); expect(screen.queryByRole('button')).not.toBeInTheDocument(); - expect(screen.queryByRole('textbox')).not.toBeInTheDocument(); + expect(screen.queryAllByRole('textbox').filter(isAuthorInput)).toHaveLength(0); expect(screen.queryByRole('radio')).not.toBeInTheDocument(); }); }); diff --git a/contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/QTIItemEditor/__tests__/QTIItemEditor.spec.js b/contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/QTIItemEditor/__tests__/QTIItemEditor.spec.js index 76a2245f49..0f37ccfaf8 100644 --- a/contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/QTIItemEditor/__tests__/QTIItemEditor.spec.js +++ b/contentcuration/contentcuration/frontend/shared/views/QTIEditor/components/QTIItemEditor/__tests__/QTIItemEditor.spec.js @@ -59,6 +59,9 @@ const renderComponent = (props = {}, slots = {}) => { }); }; +// jest_config/setup.js adds a hidden csrf input to the document. +const isAuthorInput = el => el.name !== 'csrfmiddlewaretoken'; + describe('QTIItemEditor', () => { afterEach(() => jest.restoreAllMocks()); @@ -155,7 +158,7 @@ describe('QTIItemEditor', () => { expect(screen.queryByRole('radio')).not.toBeInTheDocument(); expect(screen.queryByRole('checkbox')).not.toBeInTheDocument(); expect(screen.queryByRole('combobox')).not.toBeInTheDocument(); - expect(screen.queryByRole('textbox')).not.toBeInTheDocument(); + expect(screen.queryAllByRole('textbox').filter(isAuthorInput)).toHaveLength(0); }); }); @@ -179,7 +182,7 @@ describe('QTIItemEditor', () => { test('still renders the editor for a text-entry block holding several blanks', () => { renderDocument(MULTI_TEXT_ENTRY_ITEM_DOCUMENT, { mode: 'edit' }); expect(screen.queryByText(unsupportedItemMessage$())).not.toBeInTheDocument(); - expect(screen.getAllByRole('textbox').length).toBeGreaterThan(0); + expect(screen.queryAllByRole('textbox').filter(isAuthorInput).length).toBeGreaterThan(0); }); }); });