* test: agenda-neue - separate timezone controls assertions to allow retries * test: agenda-neue - use dom query selectors instead of first() / eq() * test: agenda-neue - playwright * test: fix playwright setup for ci * test: playwright - remove safari + fix timezone local * test: upload playwright report * test: playwright - fix trace upload * test * test: playwright - agenda search * test: fix startdate timezone * test: playwright - agenda table events * test: playwright - remove only filter * test: remove exit early flag * test: allow longer tests * test: agenda materials dialog * test: agenda filter by area/group * test: agenda calendar view * test: agenda settings * test: jump to day * test: fix agenda jump to day timezone parse * test: increase test timeout * test: remove fail fast * test: test sharding + increase delay * test: fixes * test: use macos image * test: fixes * test: agenda color assign + future + live meeting tests * test: agenda mobile tests * test: remainder of tests for playwright + optimizations * test: red line intersection accept close value * test: add delay for agenda search tests * chore: cleanup old tests + adapt build workflow * ci: fix build workflow * ci: fix build workflow order * fix: point to playwright floor plan images + readme
130 lines
6 KiB
JavaScript
130 lines
6 KiB
JavaScript
const { test, expect } = require('@playwright/test')
|
|
const { faker } = require('@faker-js/faker')
|
|
const seedrandom = require('seedrandom')
|
|
const meetingGenerator = require('../../helpers/meeting.js')
|
|
const viewports = require('../../helpers/viewports')
|
|
const { setTimeout } = require('timers/promises')
|
|
|
|
const TEST_SEED = 123
|
|
|
|
// Set randomness seed
|
|
seedrandom(TEST_SEED.toString(), { global: true })
|
|
faker.seed(TEST_SEED)
|
|
|
|
// ====================================================================
|
|
// FLOOR-PLAN-NEUE | All Viewports
|
|
// ====================================================================
|
|
|
|
test.describe('floor-plan', () => {
|
|
let meetingData
|
|
|
|
test.beforeAll(async () => {
|
|
// Generate meeting data (without schedule data)
|
|
meetingData = meetingGenerator.generateAgendaResponse({ dateMode: 'past', skipSchedule: true })
|
|
})
|
|
|
|
for (const vp of ['desktop', 'smallDesktop', 'tablet', 'mobile']) {
|
|
test(vp, async ({ page }) => {
|
|
// Intercept Meeting Data API
|
|
await page.route(`**/api/meeting/${meetingData.meeting.number}/agenda-data`, route => {
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify(meetingData)
|
|
})
|
|
})
|
|
|
|
await page.setViewportSize({
|
|
width: viewports[vp][0],
|
|
height: viewports[vp][1]
|
|
})
|
|
|
|
// Visit floor plan page and await Meeting Data API call to complete
|
|
await Promise.all([
|
|
page.waitForResponse(`**/api/meeting/${meetingData.meeting.number}/agenda-data`),
|
|
page.goto(`/meeting/${meetingData.meeting.number}/floor-plan-neue`)
|
|
])
|
|
|
|
// Wait for page to be ready
|
|
await page.locator('.floorplan h1').waitFor({ state: 'visible' })
|
|
await setTimeout(500)
|
|
|
|
// -> HEADER
|
|
|
|
await test.step(`has IETF ${meetingData.meeting.number} title`, async () => {
|
|
await expect(page.locator('.floorplan h1').first()).toContainText(`IETF ${meetingData.meeting.number} Floor Plan`)
|
|
})
|
|
await test.step('has meeting city subtitle', async () => {
|
|
await expect(page.locator('.floorplan h4').first()).toContainText(meetingData.meeting.city)
|
|
})
|
|
await test.step('has meeting date subtitle', async () => {
|
|
await expect(page.locator('.floorplan h4').first()).toContainText(/[a-zA-Z] [0-9]{1,2} - ([a-zA-Z]+ )?[0-9]{1,2}, [0-9]{4}/i)
|
|
})
|
|
|
|
// -> NAV
|
|
|
|
await test.step('has the correct navigation items', async () => {
|
|
const navItemsLocator = page.locator('.floorplan .meeting-nav > li')
|
|
await expect(navItemsLocator).toHaveCount(3)
|
|
await expect(navItemsLocator.first()).toContainText('Agenda')
|
|
await expect(navItemsLocator.nth(1)).toContainText('Floor plan')
|
|
await expect(navItemsLocator.last()).toContainText('Plaintext')
|
|
})
|
|
|
|
// -> FLOORS
|
|
|
|
await test.step('can switch between floors', async () => {
|
|
const floorsLocator = page.locator('.floorplan .floorplan-floors > .nav-link')
|
|
const floorImageLocator = page.locator('.floorplan .floorplan-plan > img')
|
|
|
|
await expect(floorsLocator).toHaveCount(meetingData.floors.length)
|
|
for (let idx = 0; idx < meetingData.floors.length; idx++) {
|
|
await expect(floorsLocator.nth(idx)).toContainText(meetingData.floors[idx].name)
|
|
await floorsLocator.nth(idx).click()
|
|
await expect(floorsLocator.nth(idx)).toHaveClass(/active/)
|
|
await expect(page.locator('.floorplan .floorplan-floors > .nav-link:not(.active)')).toHaveCount(meetingData.floors.length - 1)
|
|
// Wait for image to load + verify
|
|
await expect(floorImageLocator).toBeVisible()
|
|
await setTimeout(100)
|
|
await expect(await floorImageLocator.evaluate(node => node.naturalWidth)).toBeGreaterThan(1)
|
|
}
|
|
})
|
|
|
|
// -> ROOMS
|
|
|
|
await test.step('can select rooms', async () => {
|
|
const roomsLocator = page.locator('.floorplan .floorplan-rooms > .list-group-item')
|
|
const floorImageLocator = page.locator('.floorplan .floorplan-plan > img')
|
|
const pinLocator = page.locator('.floorplan .floorplan-plan-pin')
|
|
const floor = meetingData.floors[0]
|
|
await page.locator('.floorplan .floorplan-floors > .nav-link').first().click()
|
|
await expect(roomsLocator).toHaveCount(floor.rooms.length)
|
|
for (let idx = 0; idx < floor.rooms.length; idx++) {
|
|
// Room List
|
|
const room = floor.rooms[idx]
|
|
await expect(roomsLocator.nth(idx).locator('strong')).toContainText(room.name)
|
|
await expect(roomsLocator.nth(idx).locator('strong + small')).toContainText(room.functionalName)
|
|
await expect(roomsLocator.nth(idx).locator('.badge')).toContainText(floor.short)
|
|
await roomsLocator.nth(idx).click()
|
|
await expect(roomsLocator.nth(idx)).toHaveClass(/active/)
|
|
await expect(page.locator('.floorplan .floorplan-rooms > .list-group-item:not(.active)')).toHaveCount(floor.rooms.length - 1)
|
|
// URL query segment
|
|
await expect(page.url()).toMatch(`room=${room.slug}`)
|
|
// Pin Drop
|
|
const planxRatio = (await floorImageLocator.evaluate(node => node.width)) / floor.width
|
|
const planyRatio = (await floorImageLocator.evaluate(node => node.height)) / floor.height
|
|
await expect(pinLocator).toBeVisible()
|
|
// eslint-disable-next-line no-useless-escape, quotes
|
|
const pinMarginLeft = await page.evaluate(`parseInt(window.getComputedStyle(document.querySelector('.floorplan .floorplan-plan-pin')).getPropertyValue('margin-left').match(/\\d+/))`)
|
|
const xPos = Math.round((room.left + (room.right - room.left) / 2) * planxRatio) - 25 + pinMarginLeft
|
|
const yPos = Math.round((room.top + (room.bottom - room.top) / 2) * planyRatio) - 40
|
|
const offsetLeft = await pinLocator.evaluate(node => node.offsetLeft)
|
|
const offsetTop = await pinLocator.evaluate(node => node.offsetTop)
|
|
expect(offsetLeft).toBe(xPos)
|
|
expect(offsetTop).toBe(yPos)
|
|
}
|
|
})
|
|
})
|
|
}
|
|
})
|