Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: enable stricter tsconfig settings, fix issues #7

Merged
merged 1 commit into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
import hmppsConfig from '@ministryofjustice/eslint-config-hmpps'

export default hmppsConfig()
export default [
...hmppsConfig(),
{
rules: {
'dot-notation': 'off',
},
},
]
2 changes: 2 additions & 0 deletions integration_tests/e2e/health.cy.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { expect } from 'chai'

context('Healthcheck', () => {
context('All healthy', () => {
beforeEach(() => {
Expand Down
2 changes: 1 addition & 1 deletion integration_tests/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ declare namespace Cypress {
* Custom command to signIn. Set failOnStatusCode to false if you expect and non 200 return code
* @example cy.signIn({ failOnStatusCode: boolean })
*/
signIn(options?: { failOnStatusCode: boolean }): Chainable<AUTWindow>
signIn(options?: { failOnStatusCode: boolean }): Chainable<string>
}
}
2 changes: 1 addition & 1 deletion integration_tests/mockApis/wiremock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const url = 'http://localhost:9091/__admin'
const stubFor = (mapping: Record<string, unknown>): SuperAgentRequest =>
superagent.post(`${url}/mappings`).send(mapping)

const getMatchingRequests = body => superagent.post(`${url}/requests/find`).send(body)
const getMatchingRequests = (body: string | object | undefined) => superagent.post(`${url}/requests/find`).send(body)

const resetStubs = (): Promise<Array<Response>> =>
Promise.all([superagent.delete(`${url}/mappings`), superagent.delete(`${url}/requests`)])
Expand Down
4 changes: 3 additions & 1 deletion integration_tests/support/commands.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
Cypress.Commands.add('signIn', (options = { failOnStatusCode: true }) => {
cy.request('/')
return cy.task('getSignInUrl').then((url: string) => cy.visit(url, options))
return cy.task<string>('getSignInUrl').then((url: string) => {
cy.visit(url, options)
})
})
11 changes: 0 additions & 11 deletions integration_tests/tsconfig.json

This file was deleted.

100 changes: 100 additions & 0 deletions jest.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// eslint-disable-next-line import/no-extraneous-dependencies
import '@testing-library/jest-dom'

// @ts-expect-error setImmediate args have any types
globalThis.setImmediate = globalThis.setImmediate || ((fn, ...args) => global.setTimeout(fn, 0, ...args))

// Reset JSDOM

type AddEventListenerParams = Parameters<Document['addEventListener']>
const sideEffects = {
document: {
addEventListener: {
fn: document.addEventListener,
refs: [] as {
type: AddEventListenerParams['0']
listener: AddEventListenerParams['1']
options: AddEventListenerParams['2']
}[],
},
keys: Object.keys(document) as unknown as (keyof typeof document)[],
},
window: {
addEventListener: {
fn: window.addEventListener,
refs: [] as {
type: AddEventListenerParams['0']
listener: AddEventListenerParams['1']
options: AddEventListenerParams['2']
}[],
},
keys: Object.keys(window) as unknown as (keyof typeof window)[],
},
}

// Lifecycle Hooks
// -----------------------------------------------------------------------------
beforeAll(async () => {
// Spy addEventListener
;['document', 'window'].forEach(_obj => {
const obj: 'document' | 'window' = _obj as 'document' | 'window'
const { fn } = sideEffects[obj].addEventListener
const { refs } = sideEffects[obj].addEventListener

const addEventListenerSpy: Document['addEventListener'] = (
type: string,
listener: EventListenerOrEventListenerObject,
options: boolean | EventListenerOptions,
) => {
// Store listener reference so it can be removed during reset
refs.push({ type, listener, options })
// Call original window.addEventListener
fn(type, listener, options)
}

// Add to default key array to prevent removal during reset
sideEffects[obj].keys.push('addEventListener')

// Replace addEventListener with mock
global[obj].addEventListener = addEventListenerSpy
})
})

// Reset JSDOM. This attempts to remove side effects from tests, however it does
// not reset all changes made to globals like the window and document
// objects. Tests requiring a full JSDOM reset should be stored in separate
// files, which is only way to do a complete JSDOM reset with Jest.
beforeEach(async () => {
const rootElm = document.documentElement

// Remove attributes on root element
;[...rootElm.attributes].forEach(attr => rootElm.removeAttribute(attr.name))

// Remove elements (faster than setting innerHTML)
while (rootElm.firstChild) {
rootElm.removeChild(rootElm.firstChild)
}

// Remove global listeners and keys
;['document', 'window'].forEach(_obj => {
const obj: 'document' | 'window' = _obj as 'document' | 'window'
const { refs } = sideEffects[obj].addEventListener

refs.forEach(ref => {
const { type, listener, options } = ref
global[obj].removeEventListener(type, listener, options)
})

// need a semicolon to start here because we have semis turned off and ASI won't work and eslint tries to blend the two together
;(Object.keys(global[obj]) as unknown as (keyof (typeof global)[typeof obj])[])
.filter(key => !sideEffects[obj].keys.includes(key) && !key.includes('coverage'))
.forEach(key => {
delete global[obj][key]
})
})

// Restore base elements
rootElm.innerHTML = '<head></head><body></body>'
})

export {}
Loading
Loading