Skip to content

Commit

Permalink
feat: enable strict mode and other stricter tsconfig settings, fix is…
Browse files Browse the repository at this point in the history
…sues (#7)
  • Loading branch information
ReedSoftware authored Dec 20, 2024
1 parent a39acc2 commit d8f349b
Show file tree
Hide file tree
Showing 44 changed files with 1,390 additions and 187 deletions.
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

0 comments on commit d8f349b

Please sign in to comment.