diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 68a5f2f2..c41b6d38 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -66,6 +66,8 @@ jobs: node-version: '16.x' - name: Install dependencies run: npm ci + - name: Run linting + run: npm run lint - name: Run tests run: npm run unit - name: Upload coverage to codecov diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2b24580c..2af89bc5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -43,13 +43,14 @@ repos: - id: pyupgrade args: [--py3-plus] -# - repo: https://github.com/pre-commit/mirrors-eslint -# rev: v7.13.0 -# hooks: -# - id: eslint -# additional_dependencies: -# - eslint@7.13.0 -# args: [src] + - repo: https://github.com/pre-commit/mirrors-eslint + rev: v8.38.0 + hooks: + - id: eslint + additional_dependencies: + - eslint@8.20.0 + - eslint-config-google@0.14.0 + args: ["--fix"] - repo: local hooks: diff --git a/package.json b/package.json index 8dbdead7..02028036 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "build:ci": "npm run build:css && npm run build:jsapp", "build:css": "sass --no-source-map --no-error-css src/layout/css/style.scss src/pytest_html/resources/style.css", "build:jsapp": "browserify ./src/pytest_html/scripts/index.js > ./src/pytest_html/resources/app.js", - "build": "npm run unit && npm run build:css && npm run build:jsapp" + "build": "npm run unit && npm run build:css && npm run build:jsapp", + "lint": "eslint src/pytest_html/scripts/ testing/" }, "devDependencies": { "browserify": "^17.0.0", diff --git a/src/pytest_html/scripts/dom.js b/src/pytest_html/scripts/dom.js index 6fb0b087..bb1ae3d6 100644 --- a/src/pytest_html/scripts/dom.js +++ b/src/pytest_html/scripts/dom.js @@ -55,7 +55,7 @@ const dom = { const regex = /data-column-type="(\w+)/ const cols = Object.values(resultsTableHeader).reduce((result, value) => { - if (value.includes("sortable")) { + if (value.includes('sortable')) { const matches = regex.exec(value) if (matches) { result.push(matches[1]) @@ -82,8 +82,6 @@ const dom = { getColGroup: () => templateCollGroup.content.cloneNode(true), getResultTBody: ({ testId, id, log, duration, extras, resultsTableRow, tableHtml, result, collapsed }) => { const resultLower = result.toLowerCase() - let formattedDuration = formatDuration(duration) - formattedDuration = formatDuration < 1 ? formattedDuration.ms : formattedDuration.formatted const resultBody = templateResult.content.cloneNode(true) resultBody.querySelector('tbody').classList.add(resultLower) resultBody.querySelector('tbody').id = testId @@ -92,7 +90,8 @@ const dom = { resultBody.querySelector('.col-result').dataset.id = id resultBody.querySelector('.col-name').innerText = testId - resultBody.querySelector('.col-duration').innerText = duration < 1 ? formatDuration(duration).ms : formatDuration(duration).formatted + const formattedDuration = duration < 1 ? formatDuration(duration).ms : formatDuration(duration).formatted + resultBody.querySelector('.col-duration').innerText = formattedDuration if (log) { // Wrap lines starting with "E" with span.error to color those lines red diff --git a/src/pytest_html/scripts/main.js b/src/pytest_html/scripts/main.js index 610b193b..4e48dade 100644 --- a/src/pytest_html/scripts/main.js +++ b/src/pytest_html/scripts/main.js @@ -48,12 +48,12 @@ const renderContent = (tests) => { const { headerPops } = manager.renderData if (headerPops > 0) { // remove 'headerPops' number of header columns - findAll('#results-table-head th').splice(-headerPops).forEach(column => column.remove()) + findAll('#results-table-head th').splice(-headerPops).forEach((column) => column.remove()) // remove 'headerPops' number of row columns const resultRows = findAll('.results-table-row') resultRows.forEach((elem) => { - findAll('td:not(.extra)', elem).splice(-headerPops).forEach(column => column.remove()) + findAll('td:not(.extra)', elem).splice(-headerPops).forEach((column) => column.remove()) }) } diff --git a/src/pytest_html/scripts/sort.js b/src/pytest_html/scripts/sort.js index 0349e162..eabc4dad 100644 --- a/src/pytest_html/scripts/sort.js +++ b/src/pytest_html/scripts/sort.js @@ -8,8 +8,8 @@ const genericSort = (list, key, ascending, customOrder) => { const aValue = a.result.toLowerCase() const bValue = b.result.toLowerCase() - const aIndex = customOrder.findIndex(item => item.toLowerCase() === aValue) - const bIndex = customOrder.findIndex(item => item.toLowerCase() === bValue) + const aIndex = customOrder.findIndex((item) => item.toLowerCase() === aValue) + const bIndex = customOrder.findIndex((item) => item.toLowerCase() === bValue) // Compare the indices to determine the sort order return aIndex - bIndex diff --git a/src/pytest_html/scripts/storage.js b/src/pytest_html/scripts/storage.js index c634aa43..33ef3893 100644 --- a/src/pytest_html/scripts/storage.js +++ b/src/pytest_html/scripts/storage.js @@ -64,18 +64,18 @@ const getCollapsedCategory = (config) => { const url = new URL(window.location.href) const collapsedItems = new URLSearchParams(url.search).get('collapsed') switch (true) { - case !config && collapsedItems === null: - categories = ['passed'] - break - case collapsedItems?.length === 0 || /^["']{2}$/.test(collapsedItems): - categories = [] - break - case /^all$/.test(collapsedItems) || (collapsedItems === null && /^all$/.test(config)): - categories = [...possibleFilters] - break - default: - categories = collapsedItems?.split(',').map(item => item.toLowerCase()) || config - break + case !config && collapsedItems === null: + categories = ['passed'] + break + case collapsedItems?.length === 0 || /^["']{2}$/.test(collapsedItems): + categories = [] + break + case /^all$/.test(collapsedItems) || collapsedItems === null && /^all$/.test(config): + categories = [...possibleFilters] + break + default: + categories = collapsedItems?.split(',').map((item) => item.toLowerCase()) || config + break } } else { categories = [] diff --git a/src/pytest_html/scripts/utils.js b/src/pytest_html/scripts/utils.js index 82ff731e..a596cd0d 100644 --- a/src/pytest_html/scripts/utils.js +++ b/src/pytest_html/scripts/utils.js @@ -6,7 +6,7 @@ const formattedNumber = (number) => const formatDuration = ( totalSeconds ) => { if (totalSeconds < 1) { - return {ms: `${Math.round(totalSeconds * 1000)} ms`} + return { ms: `${Math.round(totalSeconds * 1000)} ms` } } const hours = Math.floor(totalSeconds / 3600) @@ -16,8 +16,8 @@ const formatDuration = ( totalSeconds ) => { const seconds = Math.round(remainingSeconds) return { - seconds: `${Math.round(totalSeconds)} seconds`, - formatted: `${formattedNumber(hours)}:${formattedNumber(minutes)}:${formattedNumber(seconds)}`, + seconds: `${Math.round(totalSeconds)} seconds`, + formatted: `${formattedNumber(hours)}:${formattedNumber(minutes)}:${formattedNumber(seconds)}`, } } @@ -25,7 +25,9 @@ const transformTableObj = (obj) => { const appends = {} const inserts = {} for (const key in obj) { - key.startsWith("Z") ? appends[key] = obj[key] : inserts[key] = obj[key] + if (Object.hasOwn(obj, key)) { + key.startsWith('Z') ? appends[key] = obj[key] : inserts[key] = obj[key] + } } return { appends, diff --git a/testing/unittest.js b/testing/unittest.js index 1f7d2650..268c3cdd 100644 --- a/testing/unittest.js +++ b/testing/unittest.js @@ -168,19 +168,19 @@ describe('utils tests', () => { }) describe('transformTableObj', () => { it('handles empty object', () => { - expect(transformTableObj({})).to.eql({appends: {}, inserts: {}}) + expect(transformTableObj({})).to.eql({ appends: {}, inserts: {} }) }) it('handles no appends', () => { - const expected = {1: "hello", 2: "goodbye"} - expect(transformTableObj(expected)).to.eql({appends: {}, inserts: expected}) + const expected = { 1: 'hello', 2: 'goodbye' } + expect(transformTableObj(expected)).to.eql({ appends: {}, inserts: expected }) }) it('handles no inserts', () => { - const expected = {"Z1": "hello", "Z2": "goodbye"} - expect(transformTableObj(expected)).to.eql({appends: expected, inserts: {}}) + const expected = { 'Z1': 'hello', 'Z2': 'goodbye' } + expect(transformTableObj(expected)).to.eql({ appends: expected, inserts: {} }) }) it('handles both', () => { - const expected = {appends: {"Z1": "hello", "Z2": "goodbye"}, inserts: {1: "mee", 2: "moo"}} - expect(transformTableObj({...expected.appends, ...expected.inserts})).to.eql(expected) + const expected = { appends: { 'Z1': 'hello', 'Z2': 'goodbye' }, inserts: { 1: 'mee', 2: 'moo' } } + expect(transformTableObj({ ...expected.appends, ...expected.inserts })).to.eql(expected) }) }) }) @@ -191,8 +191,8 @@ describe('Storage tests', () => { const mockWindow = (queryParam) => { const mock = { location: { - href: `https://example.com/page?${queryParam}` - } + href: `https://example.com/page?${queryParam}`, + }, } originalWindow = global.window global.window = mock @@ -224,10 +224,10 @@ describe('Storage tests', () => { }) const config = [ - { value: ['failed', 'error'], expected: ['failed', 'error'] }, - { value: ['all'], expected: storageModule.possibleFilters } + { value: ['failed', 'error'], expected: ['failed', 'error'] }, + { value: ['all'], expected: storageModule.possibleFilters }, ] - config.forEach(({value, expected}) => { + config.forEach(({ value, expected }) => { it(`handles python config: ${value}`, () => { mockWindow() const collapsedItems = storageModule.getCollapsedCategory(value) @@ -236,25 +236,25 @@ describe('Storage tests', () => { }) const precedence = [ - {query: 'collapsed=xpassed,xfailed', config: ['failed', 'error'], expected: ['xpassed', 'xfailed']}, - {query: 'collapsed=all', config: ['failed', 'error'], expected: storageModule.possibleFilters}, - {query: 'collapsed=xpassed,xfailed', config: ['all'], expected: ['xpassed', 'xfailed']}, + { query: 'collapsed=xpassed,xfailed', value: ['failed', 'error'], expected: ['xpassed', 'xfailed'] }, + { query: 'collapsed=all', value: ['failed', 'error'], expected: storageModule.possibleFilters }, + { query: 'collapsed=xpassed,xfailed', value: ['all'], expected: ['xpassed', 'xfailed'] }, ] - precedence.forEach(({query, config, expected}, index) => { + precedence.forEach(({ query, value, expected }, index) => { it(`handles python config precedence ${index + 1}`, () => { mockWindow(query) - const collapsedItems = storageModule.getCollapsedCategory(config) + const collapsedItems = storageModule.getCollapsedCategory(value) expect(collapsedItems).to.eql(expected) }) }) const falsy = [ - { param: 'collapsed' }, - { param: 'collapsed=' }, - { param: 'collapsed=""' }, - { param: 'collapsed=\'\'' } + { param: 'collapsed' }, + { param: 'collapsed=' }, + { param: 'collapsed=""' }, + { param: 'collapsed=\'\'' }, ] - falsy.forEach(({param}) => { + falsy.forEach(({ param }) => { it(`collapses none with ${param}`, () => { mockWindow(param) const collapsedItems = storageModule.getCollapsedCategory()