1366 lines
64 KiB
JavaScript
1366 lines
64 KiB
JavaScript
import { DateTime } from 'luxon'
|
|
import path from 'path'
|
|
import { find, first, isEqual, times } from 'lodash-es'
|
|
import { faker } from '@faker-js/faker'
|
|
import slugify from 'slugify'
|
|
import meetingGenerator from '../../generators/meeting'
|
|
|
|
const xslugify = (str) => slugify(str.replace('/', '-'), { lower: true, strict: true })
|
|
|
|
const TEST_SEED = 123
|
|
|
|
const viewports = {
|
|
desktop: [1536, 960],
|
|
smallDesktop: [1280, 800],
|
|
tablet: [768, 1024],
|
|
mobile: [360, 760]
|
|
}
|
|
|
|
// Set randomness seed
|
|
faker.seed(TEST_SEED)
|
|
|
|
/**
|
|
* Inject meeting info json into the page
|
|
*
|
|
* @param {*} win Window Object
|
|
* @param {*} meetingNumber Meeting Number
|
|
*/
|
|
function injectMeetingData (win, meetingNumber) {
|
|
const meetingDataScript = win.document.createElement('script')
|
|
meetingDataScript.id = 'meeting-data'
|
|
meetingDataScript.type = 'application/json'
|
|
meetingDataScript.innerHTML = `{"meetingNumber": "${meetingNumber}"}`
|
|
win.document.querySelector('head').appendChild(meetingDataScript)
|
|
}
|
|
|
|
/**
|
|
* Format URL by replacing inline variables
|
|
*
|
|
* @param {String} url Raw URL
|
|
* @param {Object} session Session Object
|
|
* @param {String} meetingNumber Meeting Number
|
|
* @returns Formatted URL
|
|
*/
|
|
function formatLinkUrl (url, session, meetingNumber) {
|
|
return url ? url.replace('{meeting.number}', meetingNumber)
|
|
.replace('{group.acronym}', session.groupAcronym)
|
|
.replace('{short}', session.short)
|
|
.replace('{order_number}', session.orderInMeeting) : url
|
|
}
|
|
|
|
/**
|
|
* Find the first URL in text matching a conference domain
|
|
*
|
|
* @param {String} txt Raw Text
|
|
* @returns First URL found
|
|
*/
|
|
function findFirstConferenceUrl (txt) {
|
|
try {
|
|
const fUrl = txt.match(urlRe)
|
|
if (fUrl && fUrl[0].length > 0) {
|
|
const pUrl = new URL(fUrl[0])
|
|
if (conferenceDomains.some(d => pUrl.hostname.endsWith(d))) {
|
|
return fUrl[0]
|
|
}
|
|
}
|
|
} catch (err) { }
|
|
return null
|
|
}
|
|
|
|
// ====================================================================
|
|
// AGENDA-NEUE (past meeting) | DESKTOP viewport
|
|
// ====================================================================
|
|
|
|
describe('meeting -> agenda-neue [past, desktop]', {
|
|
viewportWidth: viewports.desktop[0],
|
|
viewportHeight: viewports.desktop[1]
|
|
}, () => {
|
|
let meetingData = null
|
|
|
|
before(() => {
|
|
// Set clock to 2022-02-01 (month is 0-indexed)
|
|
cy.clock(new Date(2022, 1, 1))
|
|
|
|
// Generate meeting data
|
|
meetingData = meetingGenerator.generateAgendaResponse({ dateMode: 'past' })
|
|
|
|
// Intercept Meeting Data API
|
|
cy.intercept('GET', `/api/meeting/${meetingData.meeting.number}/agenda-data`, { body: meetingData }).as('getMeetingData')
|
|
|
|
// Visit agenda page
|
|
cy.visit(`/meeting/${meetingData.meeting.number}/agenda-neue`, {
|
|
onBeforeLoad: (win) => { injectMeetingData(win, meetingData.meeting.number) }
|
|
})
|
|
cy.wait('@getMeetingData')
|
|
|
|
// Fix scroll behavior
|
|
// See https://github.com/cypress-io/cypress/issues/3200
|
|
cy.document().then(document => {
|
|
const htmlElement = document.querySelector('html')
|
|
if (htmlElement) {
|
|
htmlElement.style.scrollBehavior = 'inherit'
|
|
}
|
|
})
|
|
})
|
|
|
|
// -> HEADER
|
|
|
|
it(`has IETF 123 title`, () => {
|
|
cy.get('.agenda h1').first().contains(`IETF ${meetingData.meeting.number} Meeting Agenda`)
|
|
|
|
// Take a snapshot for visual diffing
|
|
cy.percySnapshot('meeting -> agenda-neue [past, desktop]', { widths: [viewports.desktop[0]] })
|
|
})
|
|
it(`has meeting city subtitle`, () => {
|
|
cy.get('.agenda h4').first().contains(meetingData.meeting.city)
|
|
})
|
|
it(`has meeting date subtitle`, () => {
|
|
cy.get('.agenda h4').first().contains(/[a-zA-Z] [0-9]{1,2} - ([a-zA-Z]+ )?[0-9]{1,2}, [0-9]{4}/i)
|
|
})
|
|
it(`has meeting last updated datetime`, () => {
|
|
const updatedDateTime = DateTime.fromISO(meetingData.meeting.updated).setZone(meetingData.meeting.timezone).toFormat(`DD 'at' tt ZZZZ`)
|
|
cy.get('.agenda h6').first().contains(updatedDateTime)
|
|
})
|
|
|
|
// -> NAV
|
|
|
|
it(`has the correct navigation items`, () => {
|
|
cy.get('.agenda .meeting-nav > li').should('have.length', 3)
|
|
cy.get('.agenda .meeting-nav > li').first().contains('Agenda')
|
|
cy.get('.agenda .meeting-nav > li').eq(1).contains('Floor plan')
|
|
cy.get('.agenda .meeting-nav > li').last().contains('Plaintext')
|
|
})
|
|
it(`has the Settings button on the right`, () => {
|
|
cy.get('.agenda .meeting-nav').next('button').should('exist')
|
|
.and('include.text', 'Settings')
|
|
cy.window().then(win => {
|
|
cy.get('.agenda .meeting-nav').next('button').then(el => {
|
|
const btnBounds = el[0].getBoundingClientRect()
|
|
expect(btnBounds.x).to.be.greaterThan(win.innerWidth - btnBounds.width - 100)
|
|
})
|
|
})
|
|
})
|
|
|
|
// -> SCHEDULE LIST -> Header
|
|
|
|
it(`has schedule list title`, () => {
|
|
cy.get('.agenda h2').first().contains(`Schedule`)
|
|
})
|
|
it(`has info note`, () => {
|
|
cy.get('.agenda .agenda-infonote').should('exist').and('include.text', meetingData.meeting.infoNote)
|
|
})
|
|
it(`info note can be dismissed / reopened`, () => {
|
|
cy.get('.agenda .agenda-infonote > button').click()
|
|
cy.get('.agenda .agenda-infonote').should('not.exist')
|
|
cy.get('.agenda h2').first().next('button').should('exist')
|
|
cy.get('.agenda h2').first().next('button').click()
|
|
cy.get('.agenda .agenda-infonote').should('exist')
|
|
cy.get('.agenda h2').first().next('button').should('not.exist')
|
|
})
|
|
it(`has timezone selector`, () => {
|
|
cy.get('.agenda .agenda-tz-selector').should('exist')
|
|
cy.get('.agenda .agenda-tz-selector').prev().should('exist').and('include.text', 'Timezone:').prev('.bi').should('exist')
|
|
cy.get('.agenda .agenda-tz-selector > button').should('have.length', 3)
|
|
cy.get('.agenda .agenda-tz-selector > button').first().contains('Meeting')
|
|
cy.get('.agenda .agenda-tz-selector > button').eq(1).contains('Local')
|
|
cy.get('.agenda .agenda-tz-selector > button').last().contains('UTC')
|
|
cy.get('.agenda .agenda-timezone-ddn').should('exist')
|
|
})
|
|
it.skip('can change timezone', () => {
|
|
// Switch to local timezone
|
|
cy.get('.agenda .agenda-tz-selector > button').eq(1).click().should('have.class', 'n-button--primary-type')
|
|
.prev('button').should('not.have.class', 'n-button--primary-type')
|
|
const localDateTime = DateTime.fromISO(meetingData.meeting.updated).setZone('local').toFormat(`DD 'at' tt ZZZZ`)
|
|
cy.get('.agenda h6').first().contains(localDateTime)
|
|
// Switch to UTC
|
|
cy.get('.agenda .agenda-tz-selector > button').last().click().should('have.class', 'n-button--primary-type')
|
|
.prev('button').should('not.have.class', 'n-button--primary-type')
|
|
const utcDateTime = DateTime.fromISO(meetingData.meeting.updated).setZone('utc').toFormat(`DD 'at' tt ZZZZ`)
|
|
cy.get('.agenda h6').first().contains(utcDateTime)
|
|
cy.get('.agenda .agenda-timezone-ddn').contains('UTC')
|
|
// Switch back to meeting timezone
|
|
cy.get('.agenda .agenda-tz-selector > button').first().click().should('have.class', 'n-button--primary-type')
|
|
cy.get('.agenda .agenda-timezone-ddn').contains('Tokyo')
|
|
})
|
|
|
|
// -> SCHEDULE LIST -> Table Headers
|
|
|
|
it('has schedule list table headers', () => {
|
|
// Table Headers
|
|
cy.get('.agenda-table-head-time').should('exist').and('contain', 'Time')
|
|
cy.get('.agenda-table-head-location').should('exist').and('contain', 'Location')
|
|
cy.get('.agenda-table-head-event').should('exist').and('contain', 'Event')
|
|
// Day Headers
|
|
cy.get('.agenda-table-display-day').should('have.length', 7).each((el, idx) => {
|
|
const localDateTime = DateTime.fromISO(meetingData.meeting.startDate).setZone('local').plus({ days: idx }).toLocaleString(DateTime.DATE_HUGE)
|
|
cy.wrap(el).should('contain', localDateTime)
|
|
})
|
|
})
|
|
|
|
// -> SCHEDULE LIST -> Table Events
|
|
|
|
it('has schedule list table events (can take a while)', {
|
|
// This test is VERY memory-intensive, so disable DOM snapshots to prevent browser crash
|
|
numTestsKeptInMemory: 0
|
|
}, () => {
|
|
let isFirstSession = true
|
|
cy.get('tr.agenda-table-display-event').should('have.length', meetingData.schedule.length).each((el, idx) => {
|
|
// Apply small arbitrary wait every 10 rows to prevent the test UI from freezing
|
|
if (idx % 10 === 0) {
|
|
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
|
cy.wait(10)
|
|
}
|
|
const event = meetingData.schedule[idx]
|
|
const eventStart = DateTime.fromISO(event.startDateTime)
|
|
const eventEnd = eventStart.plus({ seconds: event.duration })
|
|
const eventTimeSlot = `${eventStart.toFormat('HH:mm')} - ${eventEnd.toFormat('HH:mm')}`
|
|
// --------
|
|
// Location
|
|
// --------
|
|
if (event.location?.short) {
|
|
// Has floor badge
|
|
cy.wrap(el).find('.agenda-table-cell-room > a').should('contain', event.room)
|
|
.and('have.attr', 'href', `/meeting/` + meetingData.meeting.number + `/floor-plan-neue?room=` + xslugify(event.room))
|
|
.prev('.badge').should('contain', event.location.short)
|
|
} else {
|
|
// No floor badge
|
|
cy.wrap(el).find('.agenda-table-cell-room > span:not(.badge)').should('contain', event.room)
|
|
.prev('.badge').should('not.exist')
|
|
}
|
|
// ---------------------------------------------------
|
|
// Type-specific timeslot / group / name columns tests
|
|
// ---------------------------------------------------
|
|
if (event.type === 'regular') {
|
|
// First session should have header row above it
|
|
if (isFirstSession) {
|
|
cy.wrap(el).prev('tr.agenda-table-display-session-head').should('exist')
|
|
.find('.agenda-table-cell-ts').should('contain', eventTimeSlot)
|
|
.next('.agenda-table-cell-name').should('contain', `${DateTime.fromISO(event.startDateTime).toFormat('cccc')} ${event.name}`)
|
|
}
|
|
// Timeslot
|
|
cy.wrap(el).find('.agenda-table-cell-ts').should('contain', '—')
|
|
// Group Acronym + Parent
|
|
cy.wrap(el).find('.agenda-table-cell-group > .badge').should('contain', event.groupParent.acronym)
|
|
.next('a').should('contain', event.acronym).and('have.attr', 'href', `/group/` + event.acronym + `/about/`)
|
|
// Group Name
|
|
cy.wrap(el).find('.agenda-table-cell-name').should('contain', event.groupName)
|
|
isFirstSession = false
|
|
} else {
|
|
// Timeslot
|
|
cy.wrap(el).find('.agenda-table-cell-ts').should('contain', eventTimeSlot)
|
|
// Event Name
|
|
cy.wrap(el).find('.agenda-table-cell-name').should('contain', event.name)
|
|
isFirstSession = true
|
|
}
|
|
// -----------
|
|
// Name column
|
|
// -----------
|
|
// Event icon
|
|
if (['break', 'plenary'].includes(event.type) || (event.type === 'other' && ['office hours', 'hackathon'].some(s => event.name.toLowerCase().indexOf(s) >= 0))) {
|
|
cy.wrap(el).find('.agenda-table-cell-name > i.bi').should('exist')
|
|
}
|
|
// Name link
|
|
if (event.flags.agenda) {
|
|
cy.wrap(el).find('.agenda-table-cell-name > a').should('have.attr', 'href', event.agenda.url)
|
|
}
|
|
// BoF badge
|
|
if (event.isBoF) {
|
|
cy.wrap(el).find('.agenda-table-cell-name > .badge').should('contain', 'BoF')
|
|
}
|
|
// Note
|
|
if (event.note) {
|
|
cy.wrap(el).find('.agenda-table-cell-name > .agenda-table-note').should('exist')
|
|
.find('i.bi').should('exist')
|
|
.next('span').should('contain', event.note)
|
|
}
|
|
// -----------------------
|
|
// Buttons / Status Column
|
|
// -----------------------
|
|
switch (event.status) {
|
|
// Cancelled
|
|
case 'canceled': {
|
|
cy.wrap(el).find('.agenda-table-cell-links > .badge.is-cancelled').should('contain', 'Cancelled')
|
|
break
|
|
}
|
|
// Rescheduled
|
|
case 'resched': {
|
|
cy.wrap(el).find('.agenda-table-cell-links > .badge.is-rescheduled').should('contain', 'Rescheduled')
|
|
break
|
|
}
|
|
// Scheduled
|
|
case 'sched': {
|
|
if (event.flags.showAgenda || ['regular', 'plenary'].includes(event.type)) {
|
|
cy.wrap(el).find('.agenda-table-cell-links > .agenda-table-cell-links-buttons').as('eventbuttons')
|
|
if (event.flags.agenda) {
|
|
// Show meeting materials button
|
|
cy.get('@eventbuttons').find('i.bi.bi-collection').should('exist')
|
|
// ZIP materials button
|
|
cy.get('@eventbuttons').find(`#btn-lnk-${event.id}-tar`).should('have.attr', 'href', `/meeting/${meetingData.meeting.number}/agenda/${event.acronym}-drafts.tgz`)
|
|
.children('i.bi').should('exist')
|
|
// PDF materials button
|
|
cy.get('@eventbuttons').find(`#btn-lnk-${event.id}-pdf`).should('have.attr', 'href', `/meeting/${meetingData.meeting.number}/agenda/${event.acronym}-drafts.pdf`)
|
|
.children('i.bi').should('exist')
|
|
} else if (event.type === 'regular') {
|
|
// No meeting materials yet warning badge
|
|
cy.get('@eventbuttons').find('.no-meeting-materials').should('exist')
|
|
}
|
|
// Notepad button
|
|
const hedgeDocLink = `https://notes.ietf.org/notes-ietf-${meetingData.meeting.number}-${event.type === 'plenary' ? 'plenary' : event.acronym}`
|
|
cy.get('@eventbuttons').find(`#btn-lnk-${event.id}-note`).should('have.attr', 'href', hedgeDocLink)
|
|
.children('i.bi').should('exist')
|
|
// Chat logs
|
|
cy.get('@eventbuttons').find(`#btn-lnk-${event.id}-logs`).should('have.attr', 'href', event.links.chatArchive)
|
|
.children('i.bi').should('exist')
|
|
// Recordings
|
|
for (const rec of event.links.recordings) {
|
|
if (rec.url.indexOf('audio') > 0) {
|
|
// -> Audio
|
|
cy.get('@eventbuttons').find(`#btn-lnk-${event.id}-audio-${rec.id}`).should('have.attr', 'href', rec.url)
|
|
.children('i.bi').should('exist')
|
|
} else if (rec.url.indexOf('youtu') > 0) {
|
|
// -> Youtube
|
|
cy.get('@eventbuttons').find(`#btn-lnk-${event.id}-youtube-${rec.id}`).should('have.attr', 'href', rec.url)
|
|
.children('i.bi').should('exist')
|
|
} else {
|
|
// -> Others
|
|
cy.get('@eventbuttons').find(`#btn-lnk-${event.id}-video-${rec.id}`).should('have.attr', 'href', rec.url)
|
|
.children('i.bi').should('exist')
|
|
}
|
|
}
|
|
// Video Stream
|
|
if (event.links.videoStream) {
|
|
const videoStreamLink = `https://www.meetecho.com/ietf${meetingData.meeting.number}/recordings#${event.acronym.toUpperCase()}`
|
|
cy.get('@eventbuttons').find(`#btn-lnk-${event.id}-rec`).should('have.attr', 'href', videoStreamLink)
|
|
.children('i.bi').should('exist')
|
|
}
|
|
} else {
|
|
cy.wrap(el).find('.agenda-table-cell-links > .agenda-table-cell-links-buttons').should('not.exist')
|
|
}
|
|
break
|
|
}
|
|
}
|
|
})
|
|
})
|
|
|
|
// -> SCHEDULE LIST -> Search
|
|
|
|
it('can search meetings', {
|
|
// No need to keep DOM snapshots for this test
|
|
numTestsKeptInMemory: 0
|
|
}, () => {
|
|
cy.get('.agenda-table > .agenda-table-search > button').click()
|
|
cy.get('.agenda-search').should('exist').and('be.visible')
|
|
const event = find(meetingData.schedule, s => s.type === 'regular')
|
|
const eventWithNote = find(meetingData.schedule, s => s.note)
|
|
// Search different terms
|
|
const searchTerms = [
|
|
'hack', // Should match hackathon events
|
|
event.groupAcronym, // Match group name
|
|
event.room.toLowerCase(), // Match room name
|
|
eventWithNote.note.substring(0, 10).toLowerCase() // Match partial note
|
|
]
|
|
for (const term of searchTerms) {
|
|
cy.get('.agenda-search input[type=text]').clear().type(term)
|
|
cy.get('.agenda-table .agenda-table-display-event').should('have.length.lessThan', meetingData.schedule.length)
|
|
// Let the UI update before checking each displayed row
|
|
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
|
cy.wait(1000)
|
|
cy.get('.agenda-table .agenda-table-display-event').each((el, idx) => {
|
|
cy.wrap(el).contains(term, { matchCase: false })
|
|
})
|
|
}
|
|
// Clear button
|
|
cy.get('.agenda-search button').click()
|
|
cy.get('.agenda-search input[type=text]').should('have.value', '')
|
|
cy.get('.agenda-table .agenda-table-display-event').should('have.length', meetingData.schedule.length)
|
|
// Invalid search
|
|
cy.get('.agenda-search input[type=text]').type(faker.vehicle.vin())
|
|
cy.get('.agenda-table .agenda-table-display-event').should('have.length', 0)
|
|
cy.get('.agenda-table .agenda-table-display-noresult').should('exist').and('contain', 'No event matching your search query.')
|
|
// Closing search should clear search
|
|
cy.get('.agenda-table > .agenda-table-search > button').click()
|
|
cy.get('.agenda-search').should('not.exist')
|
|
cy.get('.agenda-table .agenda-table-display-event').should('have.length', meetingData.schedule.length)
|
|
})
|
|
|
|
// -> SCHEDULE LIST -> Show Meeting Materials dialog
|
|
|
|
it('can show meeting materials dialog', () => {
|
|
const event = find(meetingData.schedule, s => s.flags.showAgenda && s.flags.agenda)
|
|
const eventStart = DateTime.fromISO(event.startDateTime)
|
|
const eventEnd = eventStart.plus({ seconds: event.duration })
|
|
// Intercept meeting materials request
|
|
const materialsUrl = (new URL(event.agenda.url)).pathname
|
|
const materialsInfo = {
|
|
url: event.agenda.url,
|
|
slides: times(5, idx => ({
|
|
id: 100000 + idx,
|
|
title: faker.commerce.productName(),
|
|
url: `/meeting/${meetingData.meeting.number}/materials/slides-${meetingData.meeting.number}-${event.acronym}-${faker.internet.domainWord()}`,
|
|
ext: ['pdf', 'html', 'md', 'txt', 'pptx'][idx]
|
|
})),
|
|
minutes: {
|
|
ext: 'md',
|
|
id: 123456,
|
|
title: 'Minutes IETF123 Testing',
|
|
url: `/meeting/${meetingData.meeting.number}/materials/minutes-${meetingData.meeting.number}-${event.acronym}-${faker.internet.domainWord()}`
|
|
}
|
|
}
|
|
cy.intercept('GET', `/api/meeting/session/${event.sessionId}/materials`, { body: materialsInfo }).as('getMaterialsInfo')
|
|
cy.intercept('GET', materialsUrl, { body: 'The internet is a series of tubes.' }).as('getMaterialsText')
|
|
cy.intercept('GET', materialsInfo.minutes.url, { body: 'One does not simply walk into mordor.' }).as('getMaterialsMinutes')
|
|
// Open dialog
|
|
cy.get(`#agenda-rowid-${event.id}`).find(`#btn-lnk-${event.id}-mat`).click()
|
|
cy.get('.agenda-eventdetails').should('exist').and('be.visible')
|
|
cy.wait('@getMaterialsText')
|
|
// Header
|
|
cy.get('.agenda-eventdetails .n-card-header__main > .detail-header > .bi').should('exist')
|
|
.next('span').should('contain', eventStart.toFormat('DDDD'))
|
|
cy.get('.agenda-eventdetails .n-card-header__extra > .detail-header > .bi').should('exist')
|
|
.next('strong').should('contain', `${eventStart.toFormat('T')} - ${eventEnd.toFormat('T')}`)
|
|
cy.get('.agenda-eventdetails .detail-title > h6 > .bi').should('exist')
|
|
.next('span').should('contain', event.name)
|
|
cy.get('.agenda-eventdetails .detail-location > .bi').should('exist')
|
|
.next('.badge').should('contain', event.location.short)
|
|
.next('span').should('contain', event.room)
|
|
// Navigation
|
|
cy.get('.agenda-eventdetails .detail-nav > a').should('have.length', 3)
|
|
.first().should('have.class', 'active')
|
|
.nextAll().should('not.have.class', 'active')
|
|
// Agenda Tab
|
|
cy.get('.agenda-eventdetails .detail-text > iframe').should('have.attr', 'src', materialsUrl)
|
|
// Slides Tab
|
|
cy.get('.agenda-eventdetails .detail-nav > a').eq(1).click()
|
|
.should('have.class', 'active')
|
|
.siblings('a').should('not.have.class', 'active')
|
|
cy.get('.agenda-eventdetails .detail-text > .list-group > .list-group-item').should('have.length', materialsInfo.slides.length).each((el, idx) => {
|
|
cy.wrap(el).should('have.attr', 'href', materialsInfo.slides[idx].url)
|
|
.children('.bi').should('have.class', `bi-filetype-${materialsInfo.slides[idx].ext}`)
|
|
.next('span').should('contain', materialsInfo.slides[idx].title)
|
|
})
|
|
// Minutes Tab
|
|
cy.get('.agenda-eventdetails .detail-nav > a').eq(2).click()
|
|
.should('have.class', 'active')
|
|
.prevAll('a').should('not.have.class', 'active')
|
|
cy.wait('@getMaterialsMinutes')
|
|
cy.get('.agenda-eventdetails .detail-text > iframe').should('have.attr', 'src', materialsInfo.minutes.url)
|
|
// Footer Buttons
|
|
const hedgeDocLink = `https://notes.ietf.org/notes-ietf-${meetingData.meeting.number}-${event.type === 'plenary' ? 'plenary' : event.acronym}`
|
|
cy.get('.agenda-eventdetails .detail-action > a').should('have.length', 3)
|
|
.first().should('contain', 'Download as tarball').should('have.attr', 'href', `/meeting/${meetingData.meeting.number}/agenda/${event.acronym}-drafts.tgz`)
|
|
.next().should('contain', 'Download as PDF').should('have.attr', 'href', `/meeting/${meetingData.meeting.number}/agenda/${event.acronym}-drafts.pdf`)
|
|
.next().should('contain', 'Notepad').should('have.attr', 'href', hedgeDocLink)
|
|
// Clicking X should close the dialog
|
|
cy.get('.agenda-eventdetails .n-card-header__extra > .detail-header > button').click()
|
|
})
|
|
|
|
// -> SCHEDULE LIST -> Show Meeting Materials dialog (EMPTY VARIANT)
|
|
|
|
it('can show meeting materials dialog (empty variant)', () => {
|
|
const event = find(meetingData.schedule, s => s.flags.showAgenda && s.flags.agenda)
|
|
// Intercept meeting materials request
|
|
const materialsUrl = (new URL(event.agenda.url)).pathname
|
|
const materialsInfo = {
|
|
url: event.agenda.url,
|
|
slides: [],
|
|
minutes: null
|
|
}
|
|
cy.intercept('GET', `/api/meeting/session/${event.sessionId}/materials`, { body: materialsInfo }).as('getMaterialsInfo')
|
|
cy.intercept('GET', materialsUrl, { body: 'The internet is a series of tubes.' }).as('getMaterialsText')
|
|
// Open dialog
|
|
cy.get(`#agenda-rowid-${event.id}`).find(`#btn-lnk-${event.id}-mat`).click()
|
|
cy.get('.agenda-eventdetails').should('exist').and('be.visible')
|
|
cy.wait('@getMaterialsText')
|
|
// Slides Tab
|
|
cy.get('.agenda-eventdetails .detail-nav > a').eq(1).click()
|
|
cy.get('.agenda-eventdetails .detail-text').should('contain', 'No slides submitted for this session.')
|
|
// Minutes Tab
|
|
cy.get('.agenda-eventdetails .detail-nav > a').eq(2).click()
|
|
cy.get('.agenda-eventdetails .detail-text').should('contain', 'No minutes submitted for this session.')
|
|
// Clicking X should close the dialog
|
|
cy.get('.agenda-eventdetails .n-card-header__extra > .detail-header > button').click()
|
|
})
|
|
|
|
// -> FILTER BY AREA/GROUP DIALOG
|
|
|
|
it('can filter by area/group', {
|
|
// This test has lot of UI element interactions and the UI can get slow with DOM snapshots, so disable it
|
|
numTestsKeptInMemory: 0
|
|
}, () => {
|
|
// Open dialog
|
|
cy.get('#agenda-quickaccess-filterbyareagroups-btn').should('exist').and('be.visible').click()
|
|
cy.get('.agenda-personalize').should('exist').and('be.visible')
|
|
// Check header elements
|
|
cy.get('.agenda-personalize .n-drawer-header__main > span').contains('Filter Areas + Groups')
|
|
cy.get('.agenda-personalize .agenda-personalize-actions > button').should('have.length', 3)
|
|
cy.get('.agenda-personalize .agenda-personalize-actions > button').first().contains('Clear Selection')
|
|
cy.get('.agenda-personalize .agenda-personalize-actions > button').eq(1).contains('Cancel')
|
|
cy.get('.agenda-personalize .agenda-personalize-actions > button').last().contains('Apply')
|
|
// Check categories
|
|
cy.get('.agenda-personalize .agenda-personalize-category').should('have.length', meetingData.categories.length)
|
|
// Check areas + groups
|
|
cy.get('.agenda-personalize .agenda-personalize-category').each((el, idx) => {
|
|
const cat = meetingData.categories[idx]
|
|
cy.wrap(el).find('.agenda-personalize-area').should('have.length', cat.length)
|
|
.each((areaEl, areaIdx) => {
|
|
// Area Button
|
|
const area = cat[areaIdx]
|
|
cy.wrap(areaEl).find('.agenda-personalize-areamain').scrollIntoView()
|
|
if (area.label) {
|
|
cy.wrap(areaEl).find('.agenda-personalize-areamain > button').should('be.visible').contains(area.label)
|
|
} else {
|
|
cy.wrap(areaEl).find('.agenda-personalize-areamain > button').should('not.exist')
|
|
}
|
|
// Group Buttons
|
|
cy.wrap(areaEl).find('.agenda-personalize-groups > button').should('have.length', area.children.length)
|
|
.each((groupEl, groupIdx) => {
|
|
const group = area.children[groupIdx]
|
|
cy.wrap(groupEl).should('be.visible').contains(group.label)
|
|
if (group.is_bof) {
|
|
cy.wrap(groupEl).should('have.class', 'is-bof')
|
|
cy.wrap(groupEl).find('.badge').should('be.visible').contains('BoF')
|
|
}
|
|
})
|
|
// Test Area Selection
|
|
if (area.label) {
|
|
cy.wrap(areaEl).find('.agenda-personalize-areamain > button').click()
|
|
cy.wrap(areaEl).find('.agenda-personalize-groups > button').should('have.class', 'is-checked')
|
|
cy.wrap(areaEl).find('.agenda-personalize-areamain > button').click()
|
|
cy.wrap(areaEl).find('.agenda-personalize-groups > button').should('not.have.class', 'is-checked')
|
|
}
|
|
// Test Group Selection
|
|
cy.wrap(areaEl).find('.agenda-personalize-groups > button').any().click()
|
|
.should('have.class', 'is-checked').click().should('not.have.class', 'is-checked')
|
|
})
|
|
})
|
|
// Test multi-toggled_by button trigger
|
|
cy.get(`.agenda-personalize .agenda-personalize-category:last .agenda-personalize-area:last .agenda-personalize-groups > button:contains('BoF')`).as('bofbtn')
|
|
cy.get('@bofbtn').click()
|
|
cy.get('.agenda-personalize .agenda-personalize-group:has(.badge)').should('have.class', 'is-checked')
|
|
cy.get('@bofbtn').click()
|
|
cy.get('.agenda-personalize .agenda-personalize-group:has(.badge)').should('not.have.class', 'is-checked')
|
|
// Clicking all groups from area then area button should unselect all
|
|
cy.get('.agenda-personalize .agenda-personalize-area:first .agenda-personalize-groups > button').click({ multiple: true })
|
|
cy.get('.agenda-personalize .agenda-personalize-area:first .agenda-personalize-areamain > button').click()
|
|
cy.get('.agenda-personalize .agenda-personalize-area:first .agenda-personalize-groups > button').should('not.have.class', 'is-checked')
|
|
// Test Clear Selection
|
|
cy.get('.agenda-personalize .agenda-personalize-group').any(10).click({ multiple: true })
|
|
cy.get('.agenda-personalize .agenda-personalize-actions > button').first().click()
|
|
cy.get('.agenda-personalize .agenda-personalize-group').should('not.have.class', 'is-checked')
|
|
// Click Cancel should hide dialog
|
|
cy.get('.agenda-personalize .agenda-personalize-actions > button').eq(1).click()
|
|
cy.get('.agenda-personalize').should('not.exist')
|
|
})
|
|
|
|
// -> PICK SESSIONS
|
|
|
|
it('can pick individual sessions', () => {
|
|
// Enter pick mode
|
|
cy.get('#agenda-quickaccess-picksessions-btn').should('be.visible').click().should('not.exist')
|
|
cy.get('#agenda-quickaccess-applypick-btn').should('be.visible')
|
|
cy.get('#agenda-quickaccess-discardpick-btn').should('be.visible')
|
|
|
|
// Pick 10 random sessions
|
|
cy.get('.agenda .agenda-table-cell-check > .n-checkbox').should('have.length', meetingData.schedule.length)
|
|
.any(10).click({ multiple: true })
|
|
cy.get('#agenda-quickaccess-applypick-btn').click().should('not.exist')
|
|
cy.get('#agenda-quickaccess-modifypick-btn').should('be.visible')
|
|
cy.get('#agenda-quickaccess-discardpick-btn').should('be.visible')
|
|
cy.get('.agenda .agenda-table-display-event').should('have.length', 10)
|
|
|
|
// Change selection (keep existing 5 + add 5 new ones)
|
|
cy.get('#agenda-quickaccess-modifypick-btn').click().should('not.exist')
|
|
cy.get('#agenda-quickaccess-applypick-btn').should('be.visible')
|
|
cy.get('#agenda-quickaccess-discardpick-btn').should('be.visible')
|
|
cy.get('.agenda .agenda-table-cell-check > .n-checkbox').should('have.length', meetingData.schedule.length)
|
|
.filter('.n-checkbox--checked').should('have.length', 10)
|
|
.take(5).click({ multiple: true })
|
|
cy.get('.agenda .agenda-table-cell-check > .n-checkbox:not(.n-checkbox--checked)').any(5).click({ multiple: true })
|
|
cy.get('#agenda-quickaccess-applypick-btn').click()
|
|
cy.get('.agenda .agenda-table-display-event').should('have.length', 10)
|
|
|
|
// Discard should clear selection
|
|
cy.get('#agenda-quickaccess-discardpick-btn').click().should('not.exist')
|
|
cy.get('#agenda-quickaccess-modifypick-btn').should('not.exist')
|
|
cy.get('#agenda-quickaccess-picksessions-btn').should('be.visible')
|
|
cy.get('.agenda .agenda-table-cell-check').should('not.exist')
|
|
cy.get('.agenda .agenda-table-display-event').should('have.length', meetingData.schedule.length)
|
|
})
|
|
|
|
// -> CALENDAR VIEW
|
|
|
|
it('can view calendar', () => {
|
|
// Open dialog
|
|
cy.get('#agenda-quickaccess-calview-btn').should('be.visible').click()
|
|
cy.get('.agenda-calendar').should('exist').and('be.visible')
|
|
// Check header elements
|
|
cy.get('.agenda-calendar .n-drawer-header__main > span').contains('Calendar View')
|
|
cy.get('.agenda-calendar .agenda-calendar-actions').as('diagheader')
|
|
cy.get('@diagheader').children('button').should('have.length', 2)
|
|
cy.get('@diagheader').children('button').first().should('include.text', 'Filter')
|
|
cy.get('@diagheader').children('button').last().should('include.text', 'Close')
|
|
// -----------------------
|
|
// Check timezone controls
|
|
// -----------------------
|
|
// cy.get('@diagheader').children('small').first().should('contain', 'Timezone')
|
|
// // Switch to local timezone
|
|
// cy.get('@diagheader').children('.n-button-group').find('button').as('tzbuttons').eq(1).click().should('have.class', 'n-button--primary-type')
|
|
// .prev('button').should('not.have.class', 'n-button--primary-type')
|
|
// const localDateTime = DateTime.fromISO(meetingData.meeting.updated).setZone('local').toFormat(`DD 'at' tt ZZZZ`)
|
|
// cy.get('.agenda h6').first().contains(localDateTime)
|
|
// // Switch to UTC
|
|
// cy.get('@tzbuttons').last().click().should('have.class', 'n-button--primary-type')
|
|
// .prev('button').should('not.have.class', 'n-button--primary-type')
|
|
// const utcDateTime = DateTime.fromISO(meetingData.meeting.updated).setZone('utc').toFormat(`DD 'at' tt ZZZZ`)
|
|
// cy.get('.agenda h6').first().contains(utcDateTime)
|
|
// // Switch back to meeting timezone
|
|
// cy.get('@tzbuttons').first().click().should('have.class', 'n-button--primary-type')
|
|
// ----------------------
|
|
// Check Filters Shortcut
|
|
// ----------------------
|
|
cy.get('@diagheader').children('button').first().click()
|
|
// Only check whether the dialog is shown. We already tested the dialog earlier.
|
|
cy.get('.agenda-personalize').should('be.visible')
|
|
// Close dialog
|
|
cy.get('.agenda-personalize .agenda-personalize-actions > button').eq(1).click()
|
|
cy.get('.agenda-personalize').should('not.exist')
|
|
// ------------------
|
|
// Check Event Dialog
|
|
// ------------------
|
|
const firstEvent = meetingData.schedule[0]
|
|
const materialsUrl = (new URL(firstEvent.agenda.url)).pathname
|
|
const materialsInfo = {
|
|
url: firstEvent.agenda.url,
|
|
slides: [],
|
|
minutes: null
|
|
}
|
|
cy.intercept('GET', `/api/meeting/session/${firstEvent.sessionId}/materials`, { body: materialsInfo }).as('getMaterialsInfo')
|
|
cy.intercept('GET', materialsUrl, { body: 'The internet is a series of tubes.' }).as('getMaterialsText')
|
|
cy.get('.agenda-calendar .fc-event').first().click()
|
|
// Only check whether the dialog is shown. We already tested the dialog earlier.
|
|
cy.get('.agenda-eventdetails').should('be.visible')
|
|
// Close dialog
|
|
cy.get('.agenda-eventdetails .n-card-header__extra > .detail-header > button').click()
|
|
// -----------
|
|
// Event Hover
|
|
// -----------
|
|
// First Event
|
|
let eventStart = DateTime.fromISO(firstEvent.startDateTime)
|
|
let eventEnd = eventStart.plus({ seconds: firstEvent.duration })
|
|
let hoverDateTime = `${eventStart.toFormat('DDDD')} from ${eventStart.toFormat('T')} to ${eventEnd.toFormat('T')}`
|
|
cy.get('.agenda-calendar .fc-event').first().realHover({ position: 'center' })
|
|
cy.get('.agenda-calendar-hint > div').first().should('include.text', firstEvent.name)
|
|
.next().should('include.text', firstEvent.location.short).and('include.text', firstEvent.room)
|
|
.next().should('include.text', hoverDateTime)
|
|
// Second Event
|
|
const secondEvent = meetingData.schedule[1]
|
|
eventStart = DateTime.fromISO(secondEvent.startDateTime)
|
|
eventEnd = eventStart.plus({ seconds: secondEvent.duration })
|
|
hoverDateTime = `${eventStart.toFormat('DDDD')} from ${eventStart.toFormat('T')} to ${eventEnd.toFormat('T')}`
|
|
cy.get('.agenda-calendar .fc-event').eq(1).realHover({ position: 'center' })
|
|
cy.get('.agenda-calendar-hint > div').first().should('include.text', secondEvent.name)
|
|
.next().should('include.text', secondEvent.location.short).and('include.text', secondEvent.room)
|
|
.next().should('include.text', hoverDateTime)
|
|
// ------------------------------
|
|
// Click Close should hide dialog
|
|
// ------------------------------
|
|
cy.get('@diagheader').children('button').last().click()
|
|
cy.get('.agenda-calendar').should('not.exist')
|
|
})
|
|
|
|
// -> SETTINGS DIALOG
|
|
|
|
it('can change settings', () => {
|
|
// Open dialog
|
|
cy.get('.meeting-nav').next('button').should('exist').and('be.visible').click()
|
|
cy.get('.agenda-settings').should('exist').and('be.visible')
|
|
// Check header elements
|
|
cy.get('.agenda-settings .n-drawer-header__main > span').contains('Agenda Settings')
|
|
cy.get('.agenda-settings .agenda-settings-actions > button').should('have.length', 2)
|
|
cy.get('.agenda-settings .agenda-settings-actions > button').first().should('be.visible')
|
|
cy.get('.agenda-settings .agenda-settings-actions > button').last().contains('Close')
|
|
// -------------------
|
|
// Check export config
|
|
// -------------------
|
|
cy.get('.agenda-settings .agenda-settings-actions > button').first().click()
|
|
cy.get('.n-dropdown-option:contains("Export Configuration")').should('exist').and('be.visible').click()
|
|
cy.readFile(path.join(Cypress.config('downloadsFolder'), 'agenda-settings.json'), { timeout: 15000 }).then(cfg => {
|
|
cy.fixture('agenda-settings.json').then(cfgValid => {
|
|
expect(isEqual(cfg, cfgValid)).to.be.true
|
|
})
|
|
})
|
|
// -------------------
|
|
// Check import config
|
|
// -------------------
|
|
// Skip test if firefox/safari since they don't support the file picker API
|
|
if (!Cypress.isBrowser('firefox') && !Cypress.isBrowser('safari')) {
|
|
cy.fixture('agenda-settings.json', { encoding: 'utf8' }).then(cfgImport => {
|
|
// Stub the native file picker
|
|
// From https://cypresstips.substack.com/p/stub-the-browser-filesystem-api
|
|
cy.window().then((win) => {
|
|
cy.stub(win, 'showOpenFilePicker').resolves([{
|
|
getFile: cy.stub().resolves({
|
|
text: cy.stub().resolves(JSON.stringify(cfgImport))
|
|
})
|
|
}])
|
|
cy.get('.agenda-settings .agenda-settings-actions > button').first().click()
|
|
cy.get('.n-dropdown-option:contains("Import Configuration")').should('exist').and('be.visible').click()
|
|
cy.get('.n-message').should('contain', 'Config imported successfully')
|
|
})
|
|
})
|
|
} else {
|
|
cy.log('Config import test skipped because this browser does not support file picker API, which is required for the test.')
|
|
}
|
|
// -----------------------
|
|
// Check timezone controls
|
|
// -----------------------
|
|
// cy.get('.agenda-settings-content > .n-divider').first().should('contain', 'Timezone').as('settings-timezone')
|
|
// // Switch to local timezone
|
|
// cy.get('@settings-timezone').next('.n-button-group').find('button').eq(1).click().should('have.class', 'n-button--primary-type')
|
|
// .prev('button').should('not.have.class', 'n-button--primary-type')
|
|
// const localDateTime = DateTime.fromISO(meetingData.meeting.updated).setZone('local').toFormat(`DD 'at' tt ZZZZ`)
|
|
// cy.get('.agenda h6').first().contains(localDateTime)
|
|
// // Switch to UTC
|
|
// cy.get('@settings-timezone').next('.n-button-group').find('button').last().click().should('have.class', 'n-button--primary-type')
|
|
// .prev('button').should('not.have.class', 'n-button--primary-type')
|
|
// const utcDateTime = DateTime.fromISO(meetingData.meeting.updated).setZone('utc').toFormat(`DD 'at' tt ZZZZ`)
|
|
// cy.get('.agenda h6').first().contains(utcDateTime)
|
|
// // Switch back to meeting timezone
|
|
// cy.get('@settings-timezone').next('.n-button-group').find('button').first().click().should('have.class', 'n-button--primary-type')
|
|
// cy.get('@settings-timezone').next('.n-button-group').next('.n-select').contains('Tokyo')
|
|
// ----------------------
|
|
// Check display controls
|
|
// ----------------------
|
|
cy.get('.agenda-settings-content > .n-divider').eq(1).should('contain', 'Display').as('settings-display')
|
|
// -> Test Current Meeting Info Note toggle
|
|
cy.get('@settings-display').nextAll('div.d-flex').eq(1).find('div[role=switch]').as('switch-infonote').click()
|
|
cy.get('.agenda .agenda-infonote').should('not.exist')
|
|
cy.get('@switch-infonote').click()
|
|
cy.get('.agenda .agenda-infonote').should('exist')
|
|
// -> Test Event Icons toggle
|
|
cy.get('@settings-display').nextAll('div.d-flex').eq(2).find('div[role=switch]').as('switch-eventicons').click()
|
|
cy.get('.agenda .agenda-event-icon').should('not.exist')
|
|
cy.get('@switch-eventicons').click()
|
|
cy.get('.agenda .agenda-event-icon').should('exist')
|
|
// -> Test Floor Indicators toggle
|
|
cy.get('@settings-display').nextAll('div.d-flex').eq(3).find('div[role=switch]').as('switch-floorind').click()
|
|
cy.get('.agenda .agenda-table-cell-room > span.badge').should('not.exist')
|
|
cy.get('@switch-floorind').click()
|
|
cy.get('.agenda .agenda-table-cell-room > span.badge').should('exist')
|
|
// -> Test Group Area Indicators toggle
|
|
cy.get('@settings-display').nextAll('div.d-flex').eq(4).find('div[role=switch]').as('switch-groupind').click()
|
|
cy.get('.agenda .agenda-table-cell-group > span.badge').should('not.exist')
|
|
cy.get('@switch-groupind').click()
|
|
cy.get('.agenda .agenda-table-cell-group > span.badge').should('exist')
|
|
// TODO: realtime red line toggle
|
|
// -> Test Bolder Text toggle
|
|
cy.get('@settings-display').nextAll('div.d-flex').eq(6).find('div[role=switch]').as('switch-boldertext').click()
|
|
cy.get('.agenda').should('have.class', 'bolder-text')
|
|
cy.get('@switch-boldertext').click()
|
|
cy.get('.agenda').should('not.have.class', 'bolder-text')
|
|
|
|
// ----------------------------
|
|
// Check calendar view controls
|
|
// ----------------------------
|
|
cy.get('.agenda-settings-content > .n-divider').eq(2).should('contain', 'Calendar View').as('settings-calendar')
|
|
// TODO: calendar view checks
|
|
// ----------------------------
|
|
// Check calendar view controls
|
|
// ----------------------------
|
|
cy.get('.agenda-settings-content > .n-divider').eq(3).should('contain', 'Custom Colors / Tags').as('settings-colors')
|
|
// ------------------------------
|
|
// Click Close should hide dialog
|
|
// ------------------------------
|
|
cy.get('.agenda-settings .agenda-settings-actions > button').last().click()
|
|
cy.get('.agenda-settings').should('not.exist')
|
|
})
|
|
|
|
// -> ADD TO CALENDAR
|
|
|
|
it('can add to calendar', () => {
|
|
cy.get('#agenda-quickaccess-addtocal-btn').should('be.visible').and('include.text', 'Add to your calendar').click()
|
|
cy.get('.n-dropdown-menu > .n-dropdown-option').should('have.length', 2)
|
|
.first().should('include.text', 'Subscribe')
|
|
.next().should('include.text', 'Download')
|
|
|
|
// Cannot test if .ics download works because of cypress bug:
|
|
// See https://github.com/cypress-io/cypress/issues/14857
|
|
|
|
// // Intercept Download ICS Call
|
|
// cy.intercept('GET', `/meeting/${meetingData.meeting.number}/agenda.ics`, {
|
|
// body: 'test',
|
|
// headers: {
|
|
// 'Content-disposition': 'attachment; filename=agenda.ics',
|
|
// 'Content-Type': 'text/calendar'
|
|
// }
|
|
// }).as('getIcs')
|
|
|
|
// // Test Download ICS
|
|
// cy.get('.n-dropdown-menu > .n-dropdown-option').eq(1).click()
|
|
// cy.wait('@getIcs')
|
|
})
|
|
|
|
// -> JUMP TO DAY
|
|
|
|
it(`can jump to specific days`, () => {
|
|
// -> Separator label
|
|
cy.get('.agenda .agenda-quickaccess-jumpto').prev('div[role=separator]').should('be.visible').and('include.text', 'Jump to...')
|
|
// -> Check nav items
|
|
cy.get('.agenda .agenda-quickaccess-jumpto > .nav-item').should('have.length', 7).as('dayjumpbuttons')
|
|
.each((el, idx) => {
|
|
const localDateTime = DateTime.fromISO(meetingData.meeting.startDate).setZone('local').plus({ days: idx }).toLocaleString(DateTime.DATE_HUGE)
|
|
cy.wrap(el).should('contain', localDateTime)
|
|
})
|
|
|
|
// Scroll to last day
|
|
// Cypress does not handle the IntersectionObserver correctly, so disable this test for now.
|
|
// See https://github.com/cypress-io/cypress/issues/3848
|
|
cy.get('@dayjumpbuttons').last().children('a').click({ scrollBehavior: false, force: true }) // .should('have.class', 'active')
|
|
cy.get('.agenda-table-display-day').last().isInViewport()
|
|
|
|
// Scroll to second day
|
|
cy.get('@dayjumpbuttons').eq(1).children('a').click({ scrollBehavior: false, force: true }) // .should('have.class', 'active')
|
|
cy.get('.agenda-table-display-day').eq(1).isInViewport()
|
|
|
|
cy.scrollTo('top')
|
|
})
|
|
|
|
// -> Color Tagging
|
|
|
|
it(`can assign colors/tags to sessions`, () => {
|
|
cy.scrollTo('top')
|
|
cy.get('.agenda .agenda-table-colorpicker').should('be.visible').click({ scrollBehavior: false })
|
|
|
|
// Check Legend
|
|
cy.get('.agenda .agenda-colorlegend').should('be.visible')
|
|
.children().first().should('include.text', 'Color Legend')
|
|
.nextAll().should('have.length', 5)
|
|
|
|
// Check color dots
|
|
cy.get('.agenda .agenda-table-display-event .agenda-table-colorindicator.is-active').should('have.length', meetingData.schedule.length)
|
|
|
|
// -------------------------
|
|
// Assign colors to sessions
|
|
// -------------------------
|
|
cy.get('.agenda .agenda-table-display-event').take(5).each((el, idx) => {
|
|
cy.wrap(el).find('.agenda-table-colorindicator').should('be.visible').click({ scrollBehavior: false, force: true })
|
|
.prev('.agenda-table-colorchoices').should('be.visible')
|
|
.children('.agenda-table-colorchoice').should('have.length', 6)
|
|
.eq(idx + 1).click({ scrollBehavior: false }).should('not.exist')
|
|
})
|
|
|
|
// Exit color assignment mode
|
|
cy.get('.agenda .agenda-table-colorpicker').click({ scrollBehavior: false })
|
|
cy.get('.agenda .agenda-table-display-event .agenda-table-colorindicator').should('have.length', 5).and('not.have.class', 'is-active')
|
|
cy.get('.agenda .agenda-colorlegend').should('be.visible')
|
|
|
|
// ----------------------------------------
|
|
// Change color legend from settings dialog
|
|
// ----------------------------------------
|
|
// Open dialog
|
|
cy.get('.meeting-nav').next('button').should('exist').and('be.visible').click()
|
|
cy.get('.agenda-settings').should('exist').and('be.visible')
|
|
// Toggle color legend switch
|
|
cy.get('.agenda-settings-content > .n-divider').eq(1).should('contain', 'Display')
|
|
.next('div.d-flex').find('div[role=switch]').as('switch-colorlegend').click()
|
|
// Legend should be hidden
|
|
cy.get('.agenda .agenda-colorlegend').should('not.exist')
|
|
// Toggle color legend back
|
|
cy.get('@switch-colorlegend').click()
|
|
// Legend should be visible
|
|
cy.get('.agenda .agenda-colorlegend').should('be.visible')
|
|
// Change color names
|
|
cy.get('#agenda-settings-colors-header').nextAll('div.d-flex').each((el, idx) => {
|
|
const newName = faker.music.genre()
|
|
cy.wrap(el).find('.n-input').clear().type(newName)
|
|
// TODO: Color names + values don't update in test mode for some reason... Watcher not triggering? Skipped for now.
|
|
// cy.get('.agenda .agenda-colorlegend').children().eq(idx + 1).should('include.text', newName)
|
|
})
|
|
// Close dialog
|
|
cy.get('.agenda-settings .agenda-settings-actions > button').last().click()
|
|
cy.get('.agenda-settings').should('not.exist')
|
|
|
|
// ---------------
|
|
// Unassign colors
|
|
// ---------------
|
|
// Re-enter color assignment mode
|
|
cy.get('.agenda .agenda-table-colorpicker').should('be.visible').click({ scrollBehavior: false })
|
|
// Remove color selection
|
|
cy.get('.agenda .agenda-table-display-event').take(5).each((el, idx) => {
|
|
cy.wrap(el).find('.agenda-table-colorindicator').should('be.visible').click({ scrollBehavior: false, force: true })
|
|
.prev('.agenda-table-colorchoices').should('be.visible')
|
|
.children('.agenda-table-colorchoice').should('have.length', 6)
|
|
.first().click({ scrollBehavior: false }).should('not.exist')
|
|
})
|
|
// Exit color assignment mode
|
|
cy.get('.agenda .agenda-table-colorpicker').click({ scrollBehavior: false })
|
|
// No colored dots should appear
|
|
cy.get('.agenda .agenda-table-display-event .agenda-table-colorindicator').should('not.exist')
|
|
// Clear all colors from Settings menu
|
|
cy.get('.meeting-nav').next('button').should('exist').and('be.visible').click()
|
|
cy.get('.agenda-settings').should('exist').and('be.visible')
|
|
cy.get('.agenda-settings .agenda-settings-actions > button').first().click()
|
|
cy.get('.n-dropdown-option:contains("Clear Color")').should('exist').and('be.visible').click()
|
|
// Color legend should no longer be displayed
|
|
cy.get('.agenda .agenda-colorlegend').should('not.exist')
|
|
cy.get('.agenda-settings').should('not.exist')
|
|
})
|
|
})
|
|
|
|
// ====================================================================
|
|
// AGENDA-NEUE (future meeting) | DESKTOP viewport
|
|
// ====================================================================
|
|
|
|
describe('meeting -> agenda-neue [future, desktop]', {
|
|
viewportWidth: viewports.desktop[0],
|
|
viewportHeight: viewports.desktop[1]
|
|
}, () => {
|
|
let meetingData = null
|
|
|
|
before(() => {
|
|
// Set clock to 2022-02-01 (month is 0-indexed)
|
|
cy.clock(new Date(2022, 1, 1))
|
|
|
|
// Generate future meeting data
|
|
meetingData = meetingGenerator.generateAgendaResponse({ dateMode: 'future' })
|
|
|
|
// Intercept Meeting Data API
|
|
cy.intercept('GET', `/api/meeting/${meetingData.meeting.number}/agenda-data`, { body: meetingData }).as('getMeetingData')
|
|
|
|
// Visit agenda page
|
|
cy.visit(`/meeting/${meetingData.meeting.number}/agenda-neue`, {
|
|
onBeforeLoad: (win) => { injectMeetingData(win, meetingData.meeting.number) }
|
|
})
|
|
cy.wait('@getMeetingData')
|
|
})
|
|
|
|
// -> SCHEDULE LIST -> Warning
|
|
|
|
it(`has current meeting warning`, () => {
|
|
cy.get('.agenda .agenda-currentwarn').should('exist').and('include.text', 'Note: IETF agendas are subject to change, up to and during a meeting.')
|
|
})
|
|
|
|
// -> SCHEDULE LIST -> Table Events
|
|
|
|
it('has schedule list table events (can take a while)', {
|
|
// This test is VERY memory-intensive, so disable DOM snapshots to prevent browser crash
|
|
numTestsKeptInMemory: 0
|
|
}, () => {
|
|
let isFirstSession = true
|
|
cy.get('tr.agenda-table-display-event').should('have.length', meetingData.schedule.length).each((el, idx) => {
|
|
// Apply small arbitrary wait every 10 rows to prevent the test UI from freezing
|
|
if (idx % 10 === 0) {
|
|
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
|
cy.wait(10)
|
|
}
|
|
const event = meetingData.schedule[idx]
|
|
|
|
// -----------------------
|
|
// Buttons / Status Column
|
|
// -----------------------
|
|
if (event.status === 'sched') {
|
|
if (event.flags.showAgenda || ['regular', 'plenary'].includes(event.type)) {
|
|
cy.wrap(el).find('.agenda-table-cell-links > .agenda-table-cell-links-buttons').as('eventbuttons')
|
|
if (event.flags.agenda) {
|
|
// Show meeting materials button
|
|
cy.get('@eventbuttons').find('i.bi.bi-collection').should('exist')
|
|
// ZIP materials button
|
|
cy.get('@eventbuttons').find(`#btn-lnk-${event.id}-tar`).should('have.attr', 'href', `/meeting/${meetingData.meeting.number}/agenda/${event.acronym}-drafts.tgz`)
|
|
.children('i.bi').should('exist')
|
|
// PDF materials button
|
|
cy.get('@eventbuttons').find(`#btn-lnk-${event.id}-pdf`).should('have.attr', 'href', `/meeting/${meetingData.meeting.number}/agenda/${event.acronym}-drafts.pdf`)
|
|
.children('i.bi').should('exist')
|
|
} else if (event.type === 'regular') {
|
|
// No meeting materials yet warning badge
|
|
cy.get('@eventbuttons').find('.no-meeting-materials').should('exist')
|
|
}
|
|
// Notepad button
|
|
const hedgeDocLink = `https://notes.ietf.org/notes-ietf-${meetingData.meeting.number}-${event.type === 'plenary' ? 'plenary' : event.acronym}`
|
|
cy.get('@eventbuttons').find(`#btn-lnk-${event.id}-note`).should('have.attr', 'href', hedgeDocLink)
|
|
.children('i.bi').should('exist')
|
|
// Chat room
|
|
cy.get('@eventbuttons').find(`#btn-lnk-${event.id}-room`).should('have.attr', 'href', event.links.chat)
|
|
.children('i.bi').should('exist')
|
|
// Video Stream
|
|
if (event.links.videoStream) {
|
|
cy.get('@eventbuttons').find(`#btn-lnk-${event.id}-video`).should('have.attr', 'href', formatLinkUrl(event.links.videoStream, event, meetingData.meeting.number))
|
|
.children('i.bi').should('exist')
|
|
}
|
|
// Onsite Tool
|
|
if (event.links.onsitetool) {
|
|
cy.get('@eventbuttons').find(`#btn-lnk-${event.id}-onsitetool`).should('have.attr', 'href', formatLinkUrl(event.links.onsitetool, event, meetingData.meeting.number))
|
|
.children('i.bi').should('exist')
|
|
}
|
|
// Audio Stream
|
|
if (event.links.audioStream) {
|
|
cy.get('@eventbuttons').find(`#btn-lnk-${event.id}-audio`).should('have.attr', 'href', formatLinkUrl(event.links.audioStream, event, meetingData.meeting.number))
|
|
.children('i.bi').should('exist')
|
|
}
|
|
// Remote Call-In
|
|
let remoteCallInUrl = null
|
|
if (event.note) {
|
|
remoteCallInUrl = findFirstConferenceUrl(event.note)
|
|
}
|
|
if (!remoteCallInUrl && event.remoteInstructions) {
|
|
remoteCallInUrl = findFirstConferenceUrl(event.remoteInstructions)
|
|
}
|
|
if (!remoteCallInUrl && event.links.webex) {
|
|
remoteCallInUrl = event.links.webex
|
|
}
|
|
if (remoteCallInUrl) {
|
|
cy.get('@eventbuttons').find(`#btn-lnk-${event.id}-remotecallin`).should('have.attr', 'href', remoteCallInUrl)
|
|
.children('i.bi').should('exist')
|
|
}
|
|
// calendar
|
|
if (event.links.calendar) {
|
|
cy.get('@eventbuttons').find(`#btn-lnk-${event.id}-calendar`).should('have.attr', 'href', event.links.calendar)
|
|
.children('i.bi').should('exist')
|
|
}
|
|
} else {
|
|
cy.wrap(el).find('.agenda-table-cell-links > .agenda-table-cell-links-buttons').should('not.exist')
|
|
}
|
|
}
|
|
})
|
|
})
|
|
})
|
|
|
|
// ====================================================================
|
|
// AGENDA-NEUE (live meeting) | DESKTOP viewport
|
|
// ====================================================================
|
|
|
|
describe('meeting -> agenda-neue [live, desktop]', {
|
|
viewportWidth: viewports.desktop[0],
|
|
viewportHeight: viewports.desktop[1]
|
|
}, () => {
|
|
let meetingData = null
|
|
const currentTime = DateTime.fromISO('2022-02-01T13:45:15', { zone: 'Asia/Tokyo' })
|
|
const liveEvents = []
|
|
let lastLiveEvent = null
|
|
|
|
before(() => {
|
|
// Set clock to 2022-02-01 (month is 0-indexed)
|
|
cy.clock(currentTime.toMillis())
|
|
|
|
// Generate live meeting data
|
|
meetingData = meetingGenerator.generateAgendaResponse({ dateMode: 'current' })
|
|
|
|
// Calculate live events
|
|
let lastEventStartTime = null
|
|
for (const event of meetingData.schedule) {
|
|
const eventStart = DateTime.fromISO(event.startDateTime, { zone: 'Asia/Tokyo' })
|
|
const eventEnd = eventStart.plus({ seconds: event.duration })
|
|
if (currentTime >= eventStart && currentTime < eventEnd) {
|
|
liveEvents.push(event)
|
|
// -> Find last event before current time
|
|
if (lastEventStartTime === eventStart.toMillis()) {
|
|
continue
|
|
} else {
|
|
lastEventStartTime = eventStart.toMillis()
|
|
lastLiveEvent = event
|
|
}
|
|
}
|
|
// -> Skip future events
|
|
if (eventStart > currentTime) {
|
|
break
|
|
}
|
|
}
|
|
|
|
// Intercept Meeting Data API
|
|
cy.intercept('GET', `/api/meeting/${meetingData.meeting.number}/agenda-data`, { body: meetingData }).as('getMeetingData')
|
|
|
|
// Visit agenda page
|
|
cy.visit(`/meeting/${meetingData.meeting.number}/agenda-neue`, {
|
|
onBeforeLoad: (win) => { injectMeetingData(win, meetingData.meeting.number) }
|
|
})
|
|
cy.wait('@getMeetingData')
|
|
|
|
// Fix scroll behavior
|
|
// See https://github.com/cypress-io/cypress/issues/3200
|
|
cy.document().then(document => {
|
|
const htmlElement = document.querySelector('html')
|
|
if (htmlElement) {
|
|
htmlElement.style.scrollBehavior = 'inherit'
|
|
}
|
|
})
|
|
})
|
|
|
|
beforeEach(() => {
|
|
cy.clock(currentTime.toMillis())
|
|
})
|
|
|
|
// -> HIGHLIGHTED LIVE SESSIONS
|
|
|
|
it(`has live sessions highlighted`, () => {
|
|
cy.get('.agenda .agenda-table-display-event.agenda-table-live').should('have.length', liveEvents.length)
|
|
})
|
|
|
|
// -> LIVE RED LINE
|
|
|
|
it(`has live red line`, () => {
|
|
cy.get('.agenda .agenda-table-redhand').should('be.visible').then(el => {
|
|
cy.get(`#agenda-rowid-${lastLiveEvent.id}`).then(elEv => {
|
|
expect(el.offsetTop).to.equal(elEv.offsetTop)
|
|
})
|
|
})
|
|
})
|
|
|
|
// -> JUMP TO NOW
|
|
|
|
it(`has jump to now button`, () => {
|
|
cy.get('.agenda .agenda-quickaccess-jumpto > .nav-item').should('have.length', 8).first().should('include.text', 'Now').click()
|
|
cy.get('.agenda .agenda-table-redhand').isInViewport()
|
|
})
|
|
|
|
// -> HIDE RED LINE
|
|
// TODO: dialog fails to render for unknown reason (but clicking manually on the window triggers the render)
|
|
// Seems like a cypress bug... Skipping for now.
|
|
it.skip(`can toggle the live red line`, () => {
|
|
// Open settings dialog
|
|
cy.get('.meeting-nav').next('button').click()
|
|
cy.get('.agenda-settings').should('exist').and('be.visible')
|
|
// Toggle red line switch
|
|
cy.get('.agenda-settings-content > .n-divider').eq(1).should('contain', 'Display')
|
|
.nextAll('div.d-flex').eq(5).find('div[role=switch]').as('switch-redline').click()
|
|
// Check red line disappeared
|
|
cy.get('.agenda .agenda-table-redhand').should('not.exist')
|
|
// Re-enable it
|
|
cy.get('@switch-redline').click()
|
|
// Check red line is visible again
|
|
cy.get('.agenda .agenda-table-redhand').should('be.visible')
|
|
// Close dialog
|
|
cy.get('.agenda-settings .agenda-settings-actions > button').last().click()
|
|
cy.get('.agenda-settings').should('not.exist')
|
|
})
|
|
})
|
|
|
|
// ====================================================================
|
|
// AGENDA-NEUE (past meeting) | SMALL DESKTOP/TABLET/MOBILE viewport
|
|
// ====================================================================
|
|
|
|
describe('meeting -> agenda-neue [past, small screens]', () => {
|
|
// Generate meeting data
|
|
const meetingData = meetingGenerator.generateAgendaResponse({ dateMode: 'past' })
|
|
|
|
for (const vp of ['smallDesktop', 'tablet', 'mobile']) {
|
|
describe(vp, {
|
|
viewportWidth: viewports[vp][0],
|
|
viewportHeight: viewports[vp][1]
|
|
}, () => {
|
|
before(() => {
|
|
// Set clock to 2022-02-01 (month is 0-indexed)
|
|
cy.clock(new Date(2022, 1, 1))
|
|
|
|
// Intercept Meeting Data API
|
|
cy.intercept('GET', `/api/meeting/${meetingData.meeting.number}/agenda-data`, { body: meetingData }).as('getMeetingData')
|
|
|
|
// Visit agenda page
|
|
cy.visit(`/meeting/${meetingData.meeting.number}/agenda-neue`, {
|
|
onBeforeLoad: (win) => { injectMeetingData(win, meetingData.meeting.number) }
|
|
})
|
|
cy.wait('@getMeetingData')
|
|
|
|
// Fix scroll behavior
|
|
// See https://github.com/cypress-io/cypress/issues/3200
|
|
cy.document().then(document => {
|
|
const htmlElement = document.querySelector('html')
|
|
if (htmlElement) {
|
|
htmlElement.style.scrollBehavior = 'inherit'
|
|
}
|
|
})
|
|
})
|
|
|
|
// -> NARROW QUICK ACCESS PANEL (smallDesktop only)
|
|
|
|
if (vp === 'smallDesktop') {
|
|
it('has narrow quick access panel', () => {
|
|
// Alternate labels for buttons
|
|
cy.get('#agenda-quickaccess-filterbyareagroups-btn').should('be.visible').and('include.text', 'Filter...')
|
|
.next('button').should('be.visible').and('include.text', 'Pick...')
|
|
cy.get('#agenda-quickaccess-calview-btn').should('be.visible').and('include.text', 'Cal View')
|
|
.next('button').should('be.visible').and('include.text', '.ics')
|
|
// -> Shorter date labels for Jump to buttons
|
|
cy.get('.agenda .agenda-quickaccess-jumpto > .nav-item').should('have.length', 7).as('dayjumpbuttons')
|
|
.each((el, idx) => {
|
|
const localDateTime = DateTime.fromISO(meetingData.meeting.startDate).setZone('local').plus({ days: idx }).toFormat('ccc LLL d')
|
|
cy.wrap(el).should('contain', localDateTime).find('i.bi').should('not.be.visible')
|
|
})
|
|
|
|
// Take a snapshot for visual diffing
|
|
cy.percySnapshot(`meeting -> agenda-neue [past, ${vp}]`, { widths: [viewports[vp][0]] })
|
|
})
|
|
}
|
|
|
|
// -> TABLET + MOBILE-specific tests
|
|
|
|
if (vp === 'tablet' || vp === 'mobile') {
|
|
|
|
// Check for elements that should not exist on smaller screens
|
|
|
|
it('has no updated date', () => {
|
|
cy.get('.agenda > h4 > h6').should('not.be.visible')
|
|
|
|
// Take a snapshot for visual diffing
|
|
cy.percySnapshot(`meeting -> agenda-neue [past, ${vp}]`, { widths: [viewports[vp][0]] })
|
|
})
|
|
|
|
it('has no timezone dropdown selector', () => {
|
|
cy.get('.agenda .agenda-tz-selector').next('.agenda-timezone-ddn').should('not.exist')
|
|
})
|
|
|
|
it('has no floor + group indicators', () => {
|
|
cy.get('.agenda .agenda-table-cell-room > .badge').should('not.be.visible')
|
|
cy.get('.agenda .agenda-table-cell-group > .badge').should('not.exist')
|
|
})
|
|
|
|
// Session buttons should be hidden in a dropdown menu
|
|
|
|
it('has session buttons dropdown', () => {
|
|
cy.get('.agenda .agenda-table-display-event .agenda-table-cell-links-buttons').each(el => {
|
|
cy.wrap(el).children().should('have.length', 1)
|
|
})
|
|
|
|
// TODO: Check for dropdown links once changed to a custom panel with standard links
|
|
})
|
|
|
|
// Bottom Mobile Bar
|
|
|
|
it('has no lateral quick access panel', () => {
|
|
cy.get('.agenda-quickaccess').should('not.exist')
|
|
})
|
|
|
|
it('has a bottom mobile bar', () => {
|
|
cy.get('.agenda-mobile-bar').should('be.visible')
|
|
.children().should('have.length', 4)
|
|
.first().should('include.text', 'Filters')
|
|
.next().should('include.text', 'Cal')
|
|
.next().should('include.text', '.ics')
|
|
.next().children().should('have.length', 1).and('have.class', 'bi')
|
|
})
|
|
|
|
it('can open the filters overlay', () => {
|
|
cy.get('.agenda-mobile-bar > button').first().click()
|
|
cy.get('.agenda-personalize').should('be.visible')
|
|
cy.get('.agenda-personalize .agenda-personalize-actions > button').eq(1).click()
|
|
cy.get('.agenda-personalize').should('not.exist')
|
|
})
|
|
|
|
it('can open the calendar view', () => {
|
|
cy.get('.agenda-mobile-bar > button').eq(1).click()
|
|
cy.get('.agenda-calendar').should('be.visible')
|
|
cy.get('.agenda-calendar .agenda-calendar-actions > button').eq(1).click()
|
|
cy.get('.agenda-calendar').should('not.exist')
|
|
})
|
|
|
|
it('can open the ics dropdown', () => {
|
|
cy.get('.agenda-mobile-bar > button').eq(2).click()
|
|
cy.get('.n-dropdown-menu > .n-dropdown-option').should('have.length', 2)
|
|
.first().should('include.text', 'Subscribe')
|
|
.next().should('include.text', 'Download')
|
|
})
|
|
|
|
it('can open the settings overlay', () => {
|
|
cy.get('.agenda-mobile-bar > button').last().click()
|
|
cy.get('.agenda-settings').should('be.visible')
|
|
cy.get('.agenda-settings .agenda-settings-actions > button').eq(1).click()
|
|
cy.get('.agenda-settings').should('not.exist')
|
|
})
|
|
}
|
|
})
|
|
}
|
|
})
|
|
|
|
// ====================================================================
|
|
// FLOOR-PLAN-NEUE | All Viewports
|
|
// ====================================================================
|
|
|
|
describe(`meeting -> floor-plan-neue`, () => {
|
|
for (const vp of ['desktop', 'smallDesktop', 'tablet', 'mobile']) {
|
|
describe(vp, {
|
|
viewportWidth: viewports[vp][0],
|
|
viewportHeight: viewports[vp][1]
|
|
}, () => {
|
|
const meetingData = meetingGenerator.generateAgendaResponse({ dateMode: 'past', skipSchedule: true })
|
|
|
|
before(() => {
|
|
cy.intercept('GET', `/api/meeting/${meetingData.meeting.number}/agenda-data`, { body: meetingData }).as('getMeetingData')
|
|
cy.visit(`/meeting/${meetingData.meeting.number}/floor-plan-neue`, {
|
|
onBeforeLoad: (win) => { injectMeetingData(win, meetingData.meeting.number) }
|
|
})
|
|
cy.wait('@getMeetingData')
|
|
})
|
|
|
|
// -> HEADER
|
|
|
|
it(`has IETF ${meetingData.meeting.number} title`, () => {
|
|
cy.get('.floorplan h1').first().contains(`IETF ${meetingData.meeting.number} Floor Plan`)
|
|
|
|
// Take a snapshot for visual diffing
|
|
cy.percySnapshot(`meeting -> floor-plan-neue [${vp}]`, { widths: [viewports[vp][0]] })
|
|
})
|
|
it(`has meeting city subtitle`, () => {
|
|
cy.get('.floorplan h4').first().contains(meetingData.meeting.city)
|
|
})
|
|
it(`has meeting date subtitle`, () => {
|
|
cy.get('.floorplan h4').first().contains(/[a-zA-Z] [0-9]{1,2} - ([a-zA-Z]+ )?[0-9]{1,2}, [0-9]{4}/i)
|
|
})
|
|
|
|
// -> NAV
|
|
|
|
it(`has the correct navigation items`, () => {
|
|
cy.get('.floorplan .meeting-nav > li').should('have.length', 3)
|
|
cy.get('.floorplan .meeting-nav > li').first().contains('Agenda')
|
|
cy.get('.floorplan .meeting-nav > li').eq(1).contains('Floor plan')
|
|
cy.get('.floorplan .meeting-nav > li').last().contains('Plaintext')
|
|
})
|
|
|
|
// -> FLOORS
|
|
|
|
it(`can switch between floors`, () => {
|
|
cy.get('.floorplan .floorplan-floors > .nav-link').should('have.length', meetingData.floors.length)
|
|
cy.get('.floorplan .floorplan-floors > .nav-link').each((el, idx) => {
|
|
cy.wrap(el).contains(meetingData.floors[idx].name)
|
|
cy.wrap(el).click()
|
|
cy.wrap(el).should('have.class', 'active')
|
|
cy.wrap(el).siblings().should('not.have.class', 'active')
|
|
// Wait for image to load + verify
|
|
cy.get('.floorplan .floorplan-plan > img').should('be.visible').and(img => expect(img[0].naturalWidth).to.be.greaterThan(1))
|
|
})
|
|
})
|
|
|
|
// -> ROOMS
|
|
|
|
it(`can select rooms`, { retries: 2 }, () => {
|
|
const floor = meetingData.floors[0]
|
|
cy.get('.floorplan .floorplan-floors > .nav-link').first().click()
|
|
cy.get('.floorplan .floorplan-rooms > .list-group-item').should('have.length', floor.rooms.length)
|
|
cy.get('.floorplan .floorplan-rooms > .list-group-item').each((el, idx) => {
|
|
// Room List
|
|
const room = floor.rooms[idx]
|
|
cy.wrap(el).find('strong').contains(room.name)
|
|
.next('small').contains(room.functionalName)
|
|
cy.wrap(el).find('.badge').should('exist').and('include.text', floor.short)
|
|
cy.wrap(el).click()
|
|
cy.wrap(el).should('have.class', 'active')
|
|
cy.wrap(el).siblings().should('not.have.class', 'active')
|
|
// URL query segment
|
|
cy.location('search').should('include', `room=${room.slug}`)
|
|
// Pin Drop
|
|
cy.window().then(win => {
|
|
cy.get('.floorplan .floorplan-plan > img').then(floorImg => {
|
|
const planxRatio = floorImg[0].width / floor.width
|
|
const planyRatio = floorImg[0].height / floor.height
|
|
cy.get('.floorplan .floorplan-plan-pin').should('exist').then(el => {
|
|
const pinMarginLeft = parseInt(win.getComputedStyle(el[0]).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
|
|
expect(el[0].offsetLeft).to.equal(xPos)
|
|
expect(el[0].offsetTop).to.equal(yPos)
|
|
})
|
|
})
|
|
})
|
|
})
|
|
})
|
|
})
|
|
}
|
|
})
|