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

[Tech] Ajout de tests de side window #2954

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ stop-stubbed-apis:
clean: docker-env
rm -Rf ./backend/target
docker compose down -v
docker compose --env-file ./infra/docker/.env -f ./infra/docker/docker-compose.monitorenv.dev.yml down -v
docker compose --env-file ./infra/docker/.env -f ./infra/docker/docker-compose.cypress.yml down -v
docker compose -f ./infra/docker/docker-compose.puppeteer.yml down -v
docker compose --env-file ./infra/docker/.env -f ./infra/docker/docker-compose.monitorenv.dev.yml down -v

check-clean-archi:
cd backend/tools && ./check-clean-architecture.sh
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { beforeEach, describe, expect, it } from '@jest/globals'
import { platform } from 'os'
import { Page } from 'puppeteer'

import { assertContains, getFirstTab, getInputContent, listenToConsole, wait, waitForSelectorWithText } from './utils'
import { assertContains, getPage, getInputContent, listenToConsole, wait, waitForSelectorWithText } from './utils'
import { SeaFrontGroup } from '../../src/domain/entities/seaFront/constants'

const TIMEOUT = 120 * 1000
Expand All @@ -17,12 +17,12 @@ const URL = `http://${WEBAPP_HOST}:${WEBAPP_PORT}/side_window`
let pageA: Page
let pageB: Page

describe('Missions Form', () => {
describe('Missions form synchronization', () => {
beforeEach(async () => {
pageA = await getFirstTab(browsers[0])
pageA = await getPage(browsers[0])
listenToConsole(pageA, 1)

pageB = await getFirstTab(browsers[1])
pageB = await getPage(browsers[1])
listenToConsole(pageB, 2)

/* eslint-disable no-restricted-syntax */
Expand Down Expand Up @@ -165,7 +165,10 @@ describe('Missions Form', () => {
*/
const finalReopen = await pageA.waitForSelector('[data-cy="reopen-mission"]')
await finalReopen.click()

await wait(5000)
await pageA.close()
await pageB.close()
},
TIMEOUT
)
Expand Down
119 changes: 119 additions & 0 deletions frontend/puppeteer/e2e/mission_side_window.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { beforeEach, describe, expect, it } from '@jest/globals'
import { platform } from 'os'
import { ElementHandle, Page } from 'puppeteer'

import { assertContains, getPage, getInputContent, getSideWindow, listenToConsole, wait } from './utils'

const TIMEOUT = 120 * 1000

const IS_CI = Boolean(process.env.CI)
const IS_DARWIN = platform() === 'darwin'
const WEBAPP_PORT = IS_CI ? 8880 : 3000
const WEBAPP_HOST = IS_DARWIN ? '0.0.0.0' : 'localhost'

const URL = `http://${WEBAPP_HOST}:${WEBAPP_PORT}/`

let mainWindow: Page

describe('Side window', () => {
beforeEach(async () => {
mainWindow = await getPage(browsers[0])
listenToConsole(mainWindow, 1)

await mainWindow.goto(URL, { waitUntil: 'domcontentloaded' })
await wait(2000)
}, 50000)

it(
'A control must replace another control previously opened in the side window',
async () => {
/**
* Open vessel sidebar Controls tab
*/
await wait(2000)
const searchVessel = await mainWindow.waitForSelector('input[placeholder="Rechercher un navire..."]')
searchVessel.click()
mainWindow.type('input[placeholder="Rechercher un navire..."]', 'pheno', { delay: 50 })

const foundVessel = await mainWindow.waitForSelector('mark')
foundVessel.click()

await wait(2000)
const controlsTab = await mainWindow.waitForSelector('*[data-cy="vessel-menu-controls"]')
controlsTab.click()

await wait(1000)
await mainWindow.waitForSelector('*[data-cy="vessel-controls-year"]')
const years = await mainWindow.$$('*[data-cy="vessel-controls-year"]')
console.log(`Found ${years.length} year`)
years.forEach(async year => {
year.click()
await wait(200)
})
await wait(1000)

/**
* Open first control in side window
*/
await mainWindow.waitForXPath("//span[contains(text(), 'Ouvrir le contrôle')]/..")
const openControlButtons = (await mainWindow.$x(
"//span[contains(text(), 'Ouvrir le contrôle')]/.."
)) as ElementHandle<HTMLButtonElement>[]
console.log(`Found ${openControlButtons.length} controls`)

const firstControlButton = openControlButtons[0]
if (!firstControlButton) {
throw new Error('The first control button is undefined')
}
await firstControlButton.click()

await wait(2000)
const sideWindow = await getSideWindow()
if (!sideWindow) {
throw new Error('sideWindow page is undefined')
}

await assertContains(sideWindow, '.Element-Tag', 'Clôturée')
await assertContains(sideWindow, '.Element-Tag', 'Appréhension espèce')
await wait(1000)

/**
* Open another control in side window
*/
await mainWindow.focus('body')
await mainWindow.waitForXPath("//span[contains(text(), 'Ouvrir le contrôle')]/..")
const openSecondControlButtons = (await mainWindow.$x(
"//span[contains(text(), 'Ouvrir le contrôle')]/.."
)) as ElementHandle<HTMLButtonElement>[]
const secondControlButton = openSecondControlButtons[1]
if (!secondControlButton) {
throw new Error('The second control button is undefined')
}
await secondControlButton.click()

/**
* Modify contact on second control
*/
const controlUnitContact = await sideWindow.waitForSelector('[name="contact_0"]')
await controlUnitContact.click({ clickCount: 3, delay: 50 })
await controlUnitContact.type('A new tel. number', { delay: 50 })
await wait(1000)

/**
* Open first control again
*/
await firstControlButton.click()

/**
* The control and mission form should be unmodified
*/
await assertContains(sideWindow, '.Element-Tag', 'Appréhension espèce')
expect(await getInputContent(sideWindow, '[name="contact_0"]')).toBe('')

await wait(5000)
await sideWindow.close()
await mainWindow.close()
},
TIMEOUT
)
})
19 changes: 15 additions & 4 deletions frontend/puppeteer/e2e/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export function listenToConsole(page: Page, index: number) {
page
.on('console', message => {
const messageType = message.type().substr(0, 3).toUpperCase()
console.log(`[Page ${index}] ${messageType}: ${message.text()}`)
console.log(`[Page ${index}] ${messageType}: ${JSON.stringify(message.text())}`)

if (messageType === 'ERR') {
console.log(message.args(), message.stackTrace())
Expand All @@ -14,6 +14,11 @@ export function listenToConsole(page: Page, index: number) {
return
}

if (message.text().includes('/wfs') || message.text().includes('areas')) {
// Do not throw an error when the app could not load a layer
return
}

throw new Error(message.text())
}
})
Expand Down Expand Up @@ -49,10 +54,10 @@ export async function getInputContent(page: Page, selector: string) {
return element && element.evaluate((el: HTMLInputElement) => el.value)
}

export async function getFirstTab(browser: Browser) {
const [firstTab] = await browser.pages()
export async function getPage(browser: Browser) {
const page = await browser.newPage()

return firstTab as Page
return page as Page
}

export function wait(ms: number) {
Expand All @@ -68,3 +73,9 @@ export async function waitForSelectorWithText<Selector extends string>(
) {
await page.waitForFunction(`document.querySelector("${selector}").innerText.includes("${text}")`, options)
}

export async function getSideWindow() {
const lastTarget = browsers[0].targets().length - 1

return browsers[0].targets()[lastTarget]?.page()
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type ControlUnitSelectProps = Readonly<{
) => Promisable<void>
onDelete: (index: number) => Promisable<void>
}>

export function ControlUnitSelect({
allAdministrationsAsOptions,
allControlUnits,
Expand All @@ -61,7 +62,7 @@ export function ControlUnitSelect({
[allControlUnits, value]
)

const isLoading = !allControlUnits.length
const isLoading = !activeAndSelectedControlUnits.length
const isEdition = selectedPath.id

const { data: engagedControlUnits = [] } = useGetEngagedControlUnitsQuery(undefined, {
Expand Down Expand Up @@ -115,7 +116,8 @@ export function ControlUnitSelect({

const handleNameChange = useCallback(
(nextName: string | undefined) => {
if (isLoading) {
const isSameValue = nextName === value.name
if (isLoading || isSameValue) {
return
}

Expand All @@ -125,7 +127,7 @@ export function ControlUnitSelect({
? {
...nextSelectedControlUnit,
contact: value.contact,
resources: value.resources
resources: []
}
: {
...INITIAL_MISSION_CONTROL_UNIT,
Expand All @@ -151,14 +153,18 @@ export function ControlUnitSelect({

const handleResourcesChange = useCallback(
(nextResources: LegacyControlUnit.LegacyControlUnitResource[] | undefined) => {
if (isLoading) {
return
}

const nextControlUnit: LegacyControlUnit.LegacyControlUnitDraft = {
...value,
resources: nextResources ?? []
}

onChange(index, nextControlUnit)
},
[value, index, onChange]
[value, index, onChange, isLoading]
)

const handleContactChange = useCallback(
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/features/SideWindow/SideWindowLauncher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export function SideWindowLauncher() {
showPrompt={isDraftDirty}
title="MonitorFish"
>
<SideWindow isFromURL={false} />
<SideWindow />
</NewWindow>
)
}
4 changes: 2 additions & 2 deletions frontend/src/features/SideWindow/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ import { setEditedReportingInSideWindow } from '../Reporting/slice'
import { getAllCurrentReportings } from '../Reporting/useCases/getAllCurrentReportings'

export type SideWindowProps = HTMLAttributes<HTMLDivElement> & {
isFromURL: boolean
isFromURL?: boolean
}
export function SideWindow({ isFromURL }: SideWindowProps) {
export function SideWindow({ isFromURL = false }: SideWindowProps) {
const dispatch = useMainAppDispatch()
// eslint-disable-next-line no-null/no-null
const wrapperRef = useRef<HTMLDivElement | null>(null)
Expand Down
2 changes: 1 addition & 1 deletion infra/docker/docker-compose.puppeteer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ services:
ports:
- 8081:8080
volumes:
- ./mappings:/home/wiremock/mappings
- ../../frontend/cypress/mappings:/home/wiremock/mappings
healthcheck:
test: [
"CMD-SHELL",
Expand Down
Loading