S 0 modules · 0 exports · 0 repositories · 13 e2e tests · 0 routes
Mobile smoke moves through common pages via the mobile nav and saves a setting Renders/ /builds /calendar /settings /to/:id /to/:id/info /u/:identifier /u/:identifier
Front page Mobile nav Tournament page Mobile nav Builds page Mobile nav Calendar page Mobile nav User page Mobile nav Settings page Arrange
Create tournament author Sendou name “Mobile Cup” start times inHours (2 ) → tournament
const tournament = await factories.TournamentFactory .create ({
authorId: ADMIN_ID ,
name: "Mobile Cup" ,
startTimes: [inHours (2 )],
});Create tournament team tournament id tournament.id member user ids N-ZAP
await factories.TournamentTeamFactory .create ({
tournamentId: tournament.id,
memberUserIds: [NZAP_TEST_ID ],
});Use a MOBILE_VIEWPORT viewport
await page.setViewportSize (MOBILE_VIEWPORT );Front page Act
Open the front page
await front.goto ();Assert
welcome banner is visible
await expect (front.locators.welcomeBanner).toBeVisible ();Mobile nav Act
Open panel “tourneys”
await mobileNav.openPanel ("tourneys" );Click event item “Mobile Cup”
await mobileNav.eventItem ("Mobile Cup" ).click ();Assert
the page URL is new RegExp (`/to/${tournament.id}` )
await expect (page).toHaveURL (new RegExp (`/to/${tournament.id}` ));no error page
await expectNoErrorPage (page);Tournament page Assert
name heading “Mobile Cup” is visible
await expect (
new TournamentPage (page).nameHeading ("Mobile Cup" ),
).toBeVisible ();Mobile nav Act
Open panel “menu”
await mobileNav.openPanel ("menu" );Click menu link “Builds”
await mobileNav.menuLink ("Builds" ).click ();Assert
the page URL is /\/builds/
await expect (page).toHaveURL (/\/builds/);no error page
await expectNoErrorPage (page);Builds page Act
on mobile the category is picked before its weapons are shown
Click category link “Shooters”
await builds.categoryLink ("Shooters" ).click ();Assert
weapon link 40 is visible
await expect (builds.weaponLink (SPLATTERSHOT_ID )).toBeVisible ();Mobile nav Act
Open panel “menu”
await mobileNav.openPanel ("menu" );Click menu link “Calendar”
await mobileNav.menuLink ("Calendar" ).click ();Assert
the page URL is /\/calendar/
await expect (page).toHaveURL (/\/calendar/);no error page
await expectNoErrorPage (page);Calendar page Assert
tournament card “Mobile Cup” is visible
await expect (
new CalendarPage (page).tournamentCard ("Mobile Cup" ),
).toBeVisible ();Mobile nav Act
Open panel “you”
await mobileNav.openPanel ("you" );Click you panel username
await mobileNav.locators.youPanelUsername.click ();Assert
the page URL is /\/u\//
await expect (page).toHaveURL (/\/u\//); no error page
await expectNoErrorPage (page);User page Assert
edit profile button is visible
await expect (userPage.locators.editProfileButton).toBeVisible ();Mobile nav Act
Open panel “you”
await mobileNav.openPanel ("you" );Click you panel settings link
await mobileNav.locators.youPanelSettingsLink.click ();Assert
the page URL is /\/settings/
await expect (page).toHaveURL (/\/settings/);no error page
await expectNoErrorPage (page);Settings page Act
Select tab “Preferences”
await settings.selectTab ("Preferences" );Check disable build ability sorting toggle
await settings.checkDisableBuildAbilitySortingToggle ();Reload
await settings.reload ();Assert
build ability sorting toggle is checked
await expect (settings.locators.buildAbilitySortingToggle).toBeChecked ();Source test ("moves through common pages via the mobile nav and saves a setting" , async ({
page,
factories,
}) => {
const tournament = await factories.TournamentFactory .create ({
authorId: ADMIN_ID ,
name: "Mobile Cup" ,
startTimes: [inHours (2 )],
});
await factories.TournamentTeamFactory .create ({
tournamentId: tournament.id,
memberUserIds: [NZAP_TEST_ID ],
});
await page.setViewportSize (MOBILE_VIEWPORT );
await impersonate (page, NZAP_TEST_ID );
const front = new FrontPage (page);
await front.goto ();
await expect (front.locators.welcomeBanner).toBeVisible ();
const mobileNav = new MobileNav (page);
await mobileNav.openPanel ("tourneys" );
await mobileNav.eventItem ("Mobile Cup" ).click ();
await expect (page).toHaveURL (new RegExp (`/to/${tournament.id}` ));
await expectNoErrorPage (page);
await expect (
new TournamentPage (page).nameHeading ("Mobile Cup" ),
).toBeVisible ();
await mobileNav.openPanel ("menu" );
await mobileNav.menuLink ("Builds" ).click ();
await expect (page).toHaveURL (/\/builds/);
await expectNoErrorPage (page);
const builds = new BuildsPage (page);
// on mobile the category is picked before its weapons are shown
await builds.categoryLink ("Shooters" ).click ();
await expect (builds.weaponLink (SPLATTERSHOT_ID )).toBeVisible ();
await mobileNav.openPanel ("menu" );
await mobileNav.menuLink ("Calendar" ).click ();
await expect (page).toHaveURL (/\/calendar/);
await expectNoErrorPage (page);
await expect (
new CalendarPage (page).tournamentCard ("Mobile Cup" ),
).toBeVisible ();
await mobileNav.openPanel ("you" );
await mobileNav.locators.youPanelUsername.click ();
await expect (page).toHaveURL (/\/u\//);
await expectNoErrorPage (page);
const userPage = new UserPage (page);
await expect (userPage.locators.editProfileButton).toBeVisible ();
await mobileNav.openPanel ("you" );
await mobileNav.locators.youPanelSettingsLink.click ();
await expect (page).toHaveURL (/\/settings/);
await expectNoErrorPage (page);
const settings = new SettingsPage (page);
await settings.selectTab ("Preferences" );
await settings.checkDisableBuildAbilitySortingToggle ();
await settings.reload ();
await expect (settings.locators.buildAbilitySortingToggle).toBeChecked ();
})Navigation Renders/ /analyzer /builds /q
Top nav menus Act
Go to “/”
await navigate ({ page, url: "/" });Top nav menus Act
Open “Play”
await topNav.open ("Play" );Assert
link “SendouQ” is visible
await expect (topNav.link ("SendouQ" )).toBeVisible ();link “Scrims” is visible
await expect (topNav.link ("Scrims" )).toBeVisible ();Act
Click link “SendouQ”
await topNav.link ("SendouQ" ).click ();Assert
the page URL is SENDOUQ_PAGE
await expect (page).toHaveURL (SENDOUQ_PAGE );link “SendouQ” is not visible
await expect (topNav.link ("SendouQ" )).not.toBeVisible ();Act
Open “Tools”
await topNav.open ("Tools" );Click link “Analyzer”
await topNav.link ("Analyzer" ).click ();Assert
the page URL is /\/analyzer/
await expect (page).toHaveURL (/\/analyzer/);Act
Open “Community”
await topNav.open ("Community" );Click link “Builds”
await topNav.link ("Builds" ).click ();Assert
the page URL is /\/builds/
await expect (page).toHaveURL (/\/builds/);Source test ("desktop navigation" , async ({ page }) => {
await impersonate (page, NZAP_TEST_ID );
await navigate ({ page, url: "/" });
const topNav = new TopNavMenus (page);
await topNav.open ("Play" );
await expect (topNav.link ("SendouQ" )).toBeVisible ();
await expect (topNav.link ("Scrims" )).toBeVisible ();
await topNav.link ("SendouQ" ).click ();
await expect (page).toHaveURL (SENDOUQ_PAGE );
await expect (topNav.link ("SendouQ" )).not.toBeVisible ();
await topNav.open ("Tools" );
await topNav.link ("Analyzer" ).click ();
await expect (page).toHaveURL (/\/analyzer/);
await topNav.open ("Community" );
await topNav.link ("Builds" ).click ();
await expect (page).toHaveURL (/\/builds/);
})Renders/
Top nav menus Mobile nav Arrange
Use a TABLET_VIEWPORT viewport
await page.setViewportSize (TABLET_VIEWPORT );Act
Go to “/”
await navigate ({ page, url: "/" });Top nav menus Act
Open “Play”
await topNav.open ("Play" );Assert
link “SendouQ” is visible
await expect (topNav.link ("SendouQ" )).toBeVisible ();Act
Close
await topNav.close ();Mobile nav Assert
tab “menu” is not visible
await expect (new MobileNav (page).tab ("menu" )).not.toBeVisible ();Source test ("tablet navigation" , async ({ page }) => {
await page.setViewportSize (TABLET_VIEWPORT );
await impersonate (page, NZAP_TEST_ID );
await navigate ({ page, url: "/" });
const topNav = new TopNavMenus (page);
await topNav.open ("Play" );
await expect (topNav.link ("SendouQ" )).toBeVisible ();
await topNav.close ();
await expect (new MobileNav (page).tab ("menu" )).not.toBeVisible ();
})Renders/ /q
Mobile nav Arrange
Use a MOBILE_VIEWPORT viewport
await page.setViewportSize (MOBILE_VIEWPORT );Act
Go to “/”
await navigate ({ page, url: "/" });Mobile nav Assert
tab “menu” is visible
await expect (mobileNav.tab ("menu" )).toBeVisible ();tab “friends” is visible
await expect (mobileNav.tab ("friends" )).toBeVisible ();tab “tourneys” is visible
await expect (mobileNav.tab ("tourneys" )).toBeVisible ();tab “chat” is visible
await expect (mobileNav.tab ("chat" )).toBeVisible ();tab “you” is visible
await expect (mobileNav.tab ("you" )).toBeVisible ();Act
Open panel “menu”
await mobileNav.openPanel ("menu" );Assert
menu link “Analyzer” is visible
await expect (mobileNav.menuLink ("Analyzer" )).toBeVisible ();menu link “Builds” is visible
await expect (mobileNav.menuLink ("Builds" )).toBeVisible ();Act
Click menu link “SendouQ”
await mobileNav.menuLink ("SendouQ" ).click ();Assert
the page URL is SENDOUQ_PAGE
await expect (page).toHaveURL (SENDOUQ_PAGE );menu link “SendouQ” is not visible
await expect (mobileNav.menuLink ("SendouQ" )).not.toBeVisible ();Source test ("mobile navigation" , async ({ page }) => {
await page.setViewportSize (MOBILE_VIEWPORT );
await impersonate (page, NZAP_TEST_ID );
await navigate ({ page, url: "/" });
const mobileNav = new MobileNav (page);
await expect (mobileNav.tab ("menu" )).toBeVisible ();
await expect (mobileNav.tab ("friends" )).toBeVisible ();
await expect (mobileNav.tab ("tourneys" )).toBeVisible ();
await expect (mobileNav.tab ("chat" )).toBeVisible ();
await expect (mobileNav.tab ("you" )).toBeVisible ();
await mobileNav.openPanel ("menu" );
await expect (mobileNav.menuLink ("Analyzer" )).toBeVisible ();
await expect (mobileNav.menuLink ("Builds" )).toBeVisible ();
await mobileNav.menuLink ("SendouQ" ).click ();
await expect (page).toHaveURL (SENDOUQ_PAGE );
await expect (mobileNav.menuLink ("SendouQ" )).not.toBeVisible ();
})my team shortcut navigates to the team page on desktop Renders/ /t/:customUrl /t/:customUrl
Side nav Arrange
Create team member user ids N-ZAP → team
const team = await factories.TeamFactory .create ({
memberUserIds: [NZAP_TEST_ID ],
});Act
Go to “/”
await navigate ({ page, url: "/" });Side nav Act
Click footer team link
await new SideNav (page).locators.footerTeamLink.click ();Assert
the page URL is teamPage (team.customUrl)
await expect (page).toHaveURL (teamPage (team.customUrl));Source test ("my team shortcut navigates to the team page on desktop" , async ({
page,
factories,
}) => {
const team = await factories.TeamFactory .create ({
memberUserIds: [NZAP_TEST_ID ],
});
await impersonate (page, NZAP_TEST_ID );
await navigate ({ page, url: "/" });
await new SideNav (page).locators.footerTeamLink.click ();
await expect (page).toHaveURL (teamPage (team.customUrl));
})mobile you panel shows the user and their team shortcut Renders/ /t/:customUrl /t/:customUrl
Mobile nav Arrange
Create team member user ids N-ZAP → team
const team = await factories.TeamFactory .create ({
memberUserIds: [NZAP_TEST_ID ],
});Use a MOBILE_VIEWPORT viewport
await page.setViewportSize (MOBILE_VIEWPORT );Act
Go to “/”
await navigate ({ page, url: "/" });Mobile nav Act
Open panel “menu”
await mobileNav.openPanel ("menu" );Switch panel “you”
await mobileNav.switchPanel ("you" );Assert
you panel username is visible
await expect (mobileNav.locators.youPanelUsername).toBeVisible ();Act
Close panel
await mobileNav.closePanel ();Assert
you panel username is not visible
await expect (mobileNav.locators.youPanelUsername).not.toBeVisible ();Act
Open panel “you”
await mobileNav.openPanel ("you" );Click you panel team link
await mobileNav.locators.youPanelTeamLink.click ();Assert
the page URL is teamPage (team.customUrl)
await expect (page).toHaveURL (teamPage (team.customUrl));Source test ("mobile you panel shows the user and their team shortcut" , async ({
page,
factories,
}) => {
const team = await factories.TeamFactory .create ({
memberUserIds: [NZAP_TEST_ID ],
});
await page.setViewportSize (MOBILE_VIEWPORT );
await impersonate (page, NZAP_TEST_ID );
await navigate ({ page, url: "/" });
const mobileNav = new MobileNav (page);
await mobileNav.openPanel ("menu" );
await mobileNav.switchPanel ("you" );
await expect (mobileNav.locators.youPanelUsername).toBeVisible ();
await mobileNav.closePanel ();
await expect (mobileNav.locators.youPanelUsername).not.toBeVisible ();
await mobileNav.openPanel ("you" );
await mobileNav.locators.youPanelTeamLink.click ();
await expect (page).toHaveURL (teamPage (team.customUrl));
})Navigation without JavaScript Runs with { javaScriptEnabled: false }
Renders/ /q
Mobile nav Arrange
Use a MOBILE_VIEWPORT viewport
await page.setViewportSize (MOBILE_VIEWPORT );Act
Go to “/”
await navigate ({ page, url: "/" });Mobile nav Assert
tab “menu” is visible
await expect (mobileNav.tab ("menu" )).toBeVisible ();tab “friends” is visible
await expect (mobileNav.tab ("friends" )).toBeVisible ();tab “tourneys” is visible
await expect (mobileNav.tab ("tourneys" )).toBeVisible ();tab “chat” is visible
await expect (mobileNav.tab ("chat" )).toBeVisible ();tab “you” is visible
await expect (mobileNav.tab ("you" )).toBeVisible ();Act
Open panel “menu”
await mobileNav.openPanel ("menu" );Assert
menu link “Analyzer” is visible
await expect (mobileNav.menuLink ("Analyzer" )).toBeVisible ();menu link “Builds” is visible
await expect (mobileNav.menuLink ("Builds" )).toBeVisible ();Act
Click menu link “SendouQ”
await mobileNav.menuLink ("SendouQ" ).click ();Assert
the page URL is SENDOUQ_PAGE
await expect (page).toHaveURL (SENDOUQ_PAGE );menu link “SendouQ” is not visible
await expect (mobileNav.menuLink ("SendouQ" )).not.toBeVisible ();Source test ("mobile navigation" , async ({ page }) => {
await page.setViewportSize (MOBILE_VIEWPORT );
await impersonate (page, NZAP_TEST_ID );
await navigate ({ page, url: "/" });
const mobileNav = new MobileNav (page);
await expect (mobileNav.tab ("menu" )).toBeVisible ();
await expect (mobileNav.tab ("friends" )).toBeVisible ();
await expect (mobileNav.tab ("tourneys" )).toBeVisible ();
await expect (mobileNav.tab ("chat" )).toBeVisible ();
await expect (mobileNav.tab ("you" )).toBeVisible ();
await mobileNav.openPanel ("menu" );
await expect (mobileNav.menuLink ("Analyzer" )).toBeVisible ();
await expect (mobileNav.menuLink ("Builds" )).toBeVisible ();
await mobileNav.menuLink ("SendouQ" ).click ();
await expect (page).toHaveURL (SENDOUQ_PAGE );
await expect (mobileNav.menuLink ("SendouQ" )).not.toBeVisible ();
})my team shortcut navigates to the team page on desktop Renders/ /t/:customUrl /t/:customUrl
Side nav Arrange
Create team member user ids N-ZAP → team
const team = await factories.TeamFactory .create ({
memberUserIds: [NZAP_TEST_ID ],
});Act
Go to “/”
await navigate ({ page, url: "/" });Side nav Act
Click footer team link
await new SideNav (page).locators.footerTeamLink.click ();Assert
the page URL is teamPage (team.customUrl)
await expect (page).toHaveURL (teamPage (team.customUrl));Source test ("my team shortcut navigates to the team page on desktop" , async ({
page,
factories,
}) => {
const team = await factories.TeamFactory .create ({
memberUserIds: [NZAP_TEST_ID ],
});
await impersonate (page, NZAP_TEST_ID );
await navigate ({ page, url: "/" });
await new SideNav (page).locators.footerTeamLink.click ();
await expect (page).toHaveURL (teamPage (team.customUrl));
})Public pages renders public pages for a logged-out visitor Renders/ /builds /builds/:slug /calendar /contributions /faq /links /scanner /support /to/:id /to/:id/info /u/:identifier /u/:identifier
Front page User page Builds page Weapon builds page Calendar page Tournament page Faq page Support page Contributions page Links page Scanner page Arrange
Create user discord id PUBLIC_USER .discordId discord name PUBLIC_USER .discordName → user
const user = await factories.UserFactory .create ({
discordId: PUBLIC_USER .discordId,
discordName: PUBLIC_USER .discordName,
});Create build owner id user.id weapon spl ids 40
await factories.BuildFactory .create ({
ownerId: user.id,
weaponSplIds: [BUILD_WEAPON_ID ],
});startTimes = [databaseTimestampNow ()]
const startTimes = [databaseTimestampNow ()];Create calendar event author Sendou name “Ink Clash Open” startTimes
await factories.CalendarEventFactory .create ({
authorId: ADMIN_ID ,
name: EVENT_NAME ,
startTimes,
});Create tournament author Sendou name “Public Pages Cup” startTimes → tournament
const tournament = await factories.TournamentFactory .create ({
authorId: ADMIN_ID ,
name: TOURNAMENT_NAME ,
startTimes,
});Front page Act
Open the front page
await front.goto ();Assert
no error page
await expectNoErrorPage (page);welcome banner is visible
await expect (front.locators.welcomeBanner).toBeVisible ();User page Act
Open the user page user.id
await userPage.goto (user.id);Assert
no error page
await expectNoErrorPage (page);username heading PUBLIC_USER .discordName is visible
await expect (
userPage.usernameHeading (PUBLIC_USER .discordName),
).toBeVisible ();Builds page Act
Open the builds page
await builds.goto ();Assert
no error page
await expectNoErrorPage (page);Act
Click weapon link 40
await builds.weaponLink (BUILD_WEAPON_ID ).click ();Weapon builds page Assert
build cards count is 1
await expect (weaponBuilds.locators.buildCards).toHaveCount (1 );Calendar page Act
Open the calendar page
await calendar.goto ();Assert
no error page
await expectNoErrorPage (page);tournament card “Ink Clash Open” is visible
await expect (calendar.tournamentCard (EVENT_NAME )).toBeVisible ();tournament card “Public Pages Cup” is visible
await expect (calendar.tournamentCard (TOURNAMENT_NAME )).toBeVisible ();Tournament page Act
Open the tournament page tournament.id
await tournamentPage.goto (tournament.id);Assert
no error page
await expectNoErrorPage (page);heading “Public Pages Cup” is visible
await expect (tournamentPage.heading (TOURNAMENT_NAME )).toBeVisible ();Faq page Act
Open the faq page
await faq.goto ();Assert
no error page
await expectNoErrorPage (page);question “What is the Plus Server?” is visible
await expect (faq.question ("What is the Plus Server?" )).toBeVisible ();Support page Act
Open the support page
await support.goto ();Assert
no error page
await expectNoErrorPage (page);patreon link is visible
await expect (support.locators.patreonLink).toBeVisible ();perk “Ad-free browsing” is visible
await expect (support.perk ("Ad-free browsing" )).toBeVisible ();Contributions page Act
Open the contributions page
await contributions.goto ();Assert
no error page
await expectNoErrorPage (page);contributor “hfcRed” is visible
await expect (contributions.contributor ("hfcRed" )).toBeVisible ();Links page Act
Open the links page
await links.goto ();Assert
no error page
await expectNoErrorPage (page);resource link “Inkipedia” is visible
await expect (links.resourceLink ("Inkipedia" )).toBeVisible ();Scanner page Act
Open the scanner page
await scanner.goto ();Assert
no error page
await expectNoErrorPage (page);the page URL is /\/scanner$/
await expect (page).toHaveURL (/\/scanner$/);start capture button is visible
await expect (scanner.locators.startCaptureButton).toBeVisible ();Source test ("renders public pages for a logged-out visitor" , async ({
page,
factories,
}) => {
const user = await factories.UserFactory .create ({
discordId: PUBLIC_USER .discordId,
discordName: PUBLIC_USER .discordName,
});
await factories.BuildFactory .create ({
ownerId: user.id,
weaponSplIds: [BUILD_WEAPON_ID ],
});
const startTimes = [databaseTimestampNow ()];
await factories.CalendarEventFactory .create ({
authorId: ADMIN_ID ,
name: EVENT_NAME ,
startTimes,
});
const tournament = await factories.TournamentFactory .create ({
authorId: ADMIN_ID ,
name: TOURNAMENT_NAME ,
startTimes,
});
const front = new FrontPage (page);
await front.goto ();
await expectNoErrorPage (page);
await expect (front.locators.welcomeBanner).toBeVisible ();
const userPage = new UserPage (page);
await userPage.goto (user.id);
await expectNoErrorPage (page);
await expect (
userPage.usernameHeading (PUBLIC_USER .discordName),
).toBeVisible ();
const builds = new BuildsPage (page);
await builds.goto ();
await expectNoErrorPage (page);
await builds.weaponLink (BUILD_WEAPON_ID ).click ();
const weaponBuilds = new WeaponBuildsPage (page);
await expect (weaponBuilds.locators.buildCards).toHaveCount (1 );
const calendar = new CalendarPage (page);
await calendar.goto ();
await expectNoErrorPage (page);
await expect (calendar.tournamentCard (EVENT_NAME )).toBeVisible ();
await expect (calendar.tournamentCard (TOURNAMENT_NAME )).toBeVisible ();
const tournamentPage = new TournamentPage (page);
await tournamentPage.goto (tournament.id);
await expectNoErrorPage (page);
await expect (tournamentPage.heading (TOURNAMENT_NAME )).toBeVisible ();
const faq = new FaqPage (page);
await faq.goto ();
await expectNoErrorPage (page);
await expect (faq.question ("What is the Plus Server?" )).toBeVisible ();
const support = new SupportPage (page);
await support.goto ();
await expectNoErrorPage (page);
await expect (support.locators.patreonLink).toBeVisible ();
await expect (support.perk ("Ad-free browsing" )).toBeVisible ();
const contributions = new ContributionsPage (page);
await contributions.goto ();
await expectNoErrorPage (page);
await expect (contributions.contributor ("hfcRed" )).toBeVisible ();
const links = new LinksPage (page);
await links.goto ();
await expectNoErrorPage (page);
await expect (links.resourceLink ("Inkipedia" )).toBeVisible ();
// anyone can capture and scan; only uploading needs a login
const scanner = new ScannerPage (page);
await scanner.goto ();
await expectNoErrorPage (page);
await expect (page).toHaveURL (/\/scanner$/);
await expect (scanner.locators.startCaptureButton).toBeVisible ();
})prompts a logged out visitor to log in when using search Weapon builds page Top right buttons Log in popover Weapon builds page Act
Open the weapon builds page “splattershot”
await weaponBuilds.goto (BUILD_WEAPON_SLUG );Top right buttons Act
Click search button
await new TopRightButtons (page).locators.searchButton.click ();Log in popover Assert
log in button is visible
await expect (logInPopover.locators.logInButton).toBeVisible ();Source test ("prompts a logged out visitor to log in when using search" , async ({
page,
}) => {
const weaponBuilds = new WeaponBuildsPage (page);
await weaponBuilds.goto (BUILD_WEAPON_SLUG );
const logInPopover = new LogInPopover (page);
await new TopRightButtons (page).locators.searchButton.click ();
await expect (logInPopover.locators.logInButton).toBeVisible ();
})lists articles and renders one by slug Renders/a /a/:slug
Articles page Article page Articles page Act
Open the articles page
await articles.goto ();Assert
no error page
await expectNoErrorPage (page);Act
Open article ARTICLE .title → article
const article = await articles.openArticle (ARTICLE .title);Article page Assert
heading ARTICLE .title is visible
await expect (article.heading (ARTICLE .title)).toBeVisible ();author link ARTICLE .author is visible
await expect (article.authorLink (ARTICLE .author)).toBeVisible ();Act
Open the article page ARTICLE .slug
await article.goto (ARTICLE .slug);Assert
heading ARTICLE .title is visible
await expect (article.heading (ARTICLE .title)).toBeVisible ();text “largest North American Splatoon LAN in history” is visible
await expect (
article.text ("largest North American Splatoon LAN in history" ),
).toBeVisible ();Source test ("lists articles and renders one by slug" , async ({ page }) => {
const articles = new ArticlesPage (page);
await articles.goto ();
await expectNoErrorPage (page);
const article = await articles.openArticle (ARTICLE .title);
await expect (article.heading (ARTICLE .title)).toBeVisible ();
await expect (article.authorLink (ARTICLE .author)).toBeVisible ();
await article.goto (ARTICLE .slug);
await expect (article.heading (ARTICLE .title)).toBeVisible ();
await expect (
article.text ("largest North American Splatoon LAN in history" ),
).toBeVisible ();
})redirects moved URLs, renders 404 for unknown ones and serves the calendar feed Renders/ /*
Error page Calendar page Arrange
Create calendar event author Sendou name “ICS Feed Cup” start times databaseTimestampNow ()
await factories.CalendarEventFactory .create ({
authorId: ADMIN_ID ,
name: ICS_EVENT_NAME ,
startTimes: [databaseTimestampNow ()],
});Error page Act
Open the error page “/u”
await errorPage.goto ("/u" );Assert
the page URL is “/?search=open&type=users”
await expect (page).toHaveURL ("/?search=open&type=users" );root count is 0
await expect (errorPage.locators.root).toHaveCount (0 );Act
Open the error page “/this-page-does-not-exist”
await errorPage.goto ("/this-page-does-not-exist" );Assert
root is visible
await expect (errorPage.locators.root).toBeVisible ();not found heading is visible
await expect (errorPage.locators.notFoundHeading).toBeVisible ();response status “/this-page-does-not-exist” is 404
expect (await errorPage.responseStatus ("/this-page-does-not-exist" )).toBe (
404 ,
);Calendar page Act
Fetch I cal feed → feed
const feed = await calendar.fetchICalFeed ();Assert
feed.status is 200
expect (feed.status).toBe (200 );feed.body contains “BEGIN:VCALENDAR”
expect (feed.body).toContain ("BEGIN:VCALENDAR" );feed.body contains “ICS Feed Cup”
expect (feed.body).toContain (ICS_EVENT_NAME );Source test ("redirects moved URLs, renders 404 for unknown ones and serves the calendar feed" , async ({
page,
factories,
}) => {
await factories.CalendarEventFactory .create ({
authorId: ADMIN_ID ,
name: ICS_EVENT_NAME ,
startTimes: [databaseTimestampNow ()],
});
const errorPage = new ErrorPage (page);
await errorPage.goto ("/u" );
await expect (page).toHaveURL ("/?search=open&type=users" );
await expect (errorPage.locators.root).toHaveCount (0 );
await errorPage.goto ("/this-page-does-not-exist" );
await expect (errorPage.locators.root).toBeVisible ();
await expect (errorPage.locators.notFoundHeading).toBeVisible ();
expect (await errorPage.responseStatus ("/this-page-does-not-exist" )).toBe (
404 ,
);
const calendar = new CalendarPage (page);
const feed = await calendar.fetchICalFeed ();
expect (feed.status).toBe (200 );
expect (feed.body).toContain ("BEGIN:VCALENDAR" );
expect (feed.body).toContain (ICS_EVENT_NAME );
})Welcome navigates to the welcome page via the front page banner when not logged in Renders/ /welcome
Front page Welcome page Front page Act
Open the front page
await front.goto ();Open welcome banner → welcome
const welcome = await front.openWelcomeBanner ();Welcome page Assert
heading is visible
await expect (welcome.locators.heading).toBeVisible ();Source test ("navigates to the welcome page via the front page banner when not logged in" , async ({
page,
}) => {
const front = new FrontPage (page);
await front.goto ();
const welcome = await front.openWelcomeBanner ();
await expect (welcome.locators.heading).toBeVisible ();
})FrontPage.gotoe2e/pages/front-page/front-page.ts:19
No JSDoc
async goto () {
await navigate ({ page: this .page, url: "/" });
}FrontPage.locators.welcomeBannere2e/pages/front-page/front-page.ts:13
No JSDoc
page.getByRole ("link" , {
name: "New to competitive Splatoon? Start here!" ,
}) MobileNav.openPanele2e/pages/layout/mobile-nav.ts:53
No JSDoc
async openPanel (panel: Panel ) {
await this .tab (panel).click ();
await this .settleAnimations ();
}MobileNav.eventIteme2e/pages/layout/mobile-nav.ts:91
No JSDoc
eventItem (name: string ) {
return this .openPanelDialog.getByRole ("link" , { name });
}expectNoErrorPagee2e/helpers/playwright.ts:741
export async function expectNoErrorPage (page: Page ) {
await expect (page.getByTestId ("error-page" )).toHaveCount (0 );
}TournamentPage.nameHeadinge2e/pages/tournament/tournament-page.ts:29
No JSDoc
nameHeading (name: string ) {
return this .page.getByRole ("heading" , { level: 1 , name });
}MobileNav.menuLinke2e/pages/layout/mobile-nav.ts:83
No JSDoc
menuLink (name: string ) {
return this .locators.menuPanel.getByRole ("link" , { name });
}BuildsPage.categoryLinke2e/pages/builds/builds-page.ts:17
No JSDoc
categoryLink (name: string ) {
return this .page.getByRole ("main" ).getByRole ("link" , { name, exact: true });
}BuildsPage.weaponLinke2e/pages/builds/builds-page.ts:21
No JSDoc
weaponLink (weaponSplId: MainWeaponId ) {
return this .page.getByTestId (`weapon-${weaponSplId}-link` );
}CalendarPage.tournamentCarde2e/pages/calendar/calendar-page.ts:39
No JSDoc
tournamentCard (name: string ) {
return this .locators.tournamentCards.filter ({ hasText: name });
}MobileNav.locators.youPanelUsernamee2e/pages/layout/mobile-nav.ts:33
No JSDoc
page.locator ("[class*='youPanelUsername']" ) UserPage.locators.editProfileButtone2e/pages/user/user-page.ts:21
No JSDoc
page.getByRole ("link" , { name: "Edit Profile" }) MobileNav.locators.youPanelSettingsLinke2e/pages/layout/mobile-nav.ts:34
No JSDoc
this .openPanelDialog.getByRole ("link" , {
name: "Settings" ,
})SettingsPage.selectTabe2e/pages/settings/settings-page.ts:66
No JSDoc
async selectTab (
name: "Match profile" | "Preferences" | "Locale" | "Theme" | "Sounds" ,
) {
await this .page.getByRole ("tab" , { name }).click ();
}SettingsPage.checkDisableBuildAbilitySortingTogglee2e/pages/settings/settings-page.ts:78
async checkDisableBuildAbilitySortingToggle () {
await waitForPOSTResponse (this .page, () =>
this .buildAbilitySortingForm.check ("newValue" ),
);
}SettingsPage.reloade2e/pages/settings/settings-page.ts:146
No JSDoc
async reload () {
await this .page.reload ();
await expectIsHydrated (this .page);
}SettingsPage.locators.buildAbilitySortingTogglee2e/pages/settings/settings-page.ts:34
No JSDoc
page.getByLabel (
this .buildAbilitySortingForm.getLabel ("newValue" ),
) FrontPagee2e/pages/front-page/front-page.ts:6
MobileNave2e/pages/layout/mobile-nav.ts:21
TournamentPagee2e/pages/tournament/tournament-page.ts:7
No JSDoc
BuildsPagee2e/pages/builds/builds-page.ts:6
No JSDoc
CalendarPagee2e/pages/calendar/calendar-page.ts:14
UserPagee2e/pages/user/user-page.ts:12
No JSDoc
SettingsPagee2e/pages/settings/settings-page.ts:18
TopNavMenus.opene2e/pages/layout/top-nav-menus.ts:19
No JSDoc
async open (category: Category ) {
await this .page.getByRole ("button" , { name: category }).click ();
}TopNavMenus.linke2e/pages/layout/top-nav-menus.ts:27
No JSDoc
link (name: string ) {
return this .locators.openMenu.getByRole ("link" , { name });
}TopNavMenuse2e/pages/layout/top-nav-menus.ts:6
TopNavMenus.closee2e/pages/layout/top-nav-menus.ts:23
No JSDoc
async close () {
await this .page.keyboard.press ("Escape" );
}MobileNav.tabe2e/pages/layout/mobile-nav.ts:44
No JSDoc
tab (panel: Panel ) {
return this .page.getByRole ("button" , { name: TAB_NAMES [panel] });
}SideNav.locators.footerTeamLinke2e/pages/layout/side-nav.ts:24
No JSDoc
this .root.getByRole ("link" , { name: "My team" })SideNave2e/pages/layout/side-nav.ts:11
MobileNav.switchPanele2e/pages/layout/mobile-nav.ts:59
async switchPanel (panel: Panel ) {
await this .tab (panel).click ();
await this .settleAnimations ();
}MobileNav.closePanele2e/pages/layout/mobile-nav.ts:64
No JSDoc
async closePanel () {
await this .settleAnimations ();
await this .openPanelDialog
.getByRole ("button" , { name: "Close" , exact: true })
.click ();
}MobileNav.locators.youPanelTeamLinke2e/pages/layout/mobile-nav.ts:37
No JSDoc
this .openPanelDialog.getByRole ("link" , {
name: "My team" ,
})UserPage.gotoe2e/pages/user/user-page.ts:35
No JSDoc
async goto (userId: number ) {
await navigate ({ page: this .page, url: userPage ({ id: userId }) });
}UserPage.usernameHeadinge2e/pages/user/user-page.ts:94
No JSDoc
usernameHeading (username: string ) {
return this .page.getByRole ("heading" , { name: username });
}BuildsPage.gotoe2e/pages/builds/builds-page.ts:13
No JSDoc
async goto () {
await navigate ({ page: this .page, url: BUILDS_PAGE });
}WeaponBuildsPage.locators.buildCardse2e/pages/builds/weapon-builds-page.ts:14
No JSDoc
page.getByTestId ("build-card" ) CalendarPage.gotoe2e/pages/calendar/calendar-page.ts:35
async goto (dayMonthYear?: DayMonthYear ) {
await navigate ({ page: this .page, url: calendarPage ({ dayMonthYear }) });
}TournamentPage.gotoe2e/pages/tournament/tournament-page.ts:21
No JSDoc
async goto (tournamentId: number ) {
await navigate ({ page: this .page, url: tournamentPage (tournamentId) });
}TournamentPage.headinge2e/pages/tournament/tournament-page.ts:25
No JSDoc
heading (name: string ) {
return this .page.getByRole ("heading" , { level: 1 , name });
}FaqPage.gotoe2e/pages/info/faq-page.ts:13
No JSDoc
async goto () {
await navigate ({ page: this .page, url: FAQ_PAGE });
}FaqPage.questione2e/pages/info/faq-page.ts:17
No JSDoc
question (text: string ) {
return this .page.getByText (text);
}SupportPage.gotoe2e/pages/info/support-page.ts:17
No JSDoc
async goto () {
await navigate ({ page: this .page, url: SUPPORT_PAGE });
}SupportPage.locators.patreonLinke2e/pages/info/support-page.ts:13
No JSDoc
page.getByRole ("link" , { name: "Support on Patreon" }) SupportPage.perke2e/pages/info/support-page.ts:21
No JSDoc
perk (name: string ) {
return this .page.getByText (name, { exact: true });
}ContributionsPage.gotoe2e/pages/info/contributions-page.ts:13
No JSDoc
async goto () {
await navigate ({ page: this .page, url: CONTRIBUTIONS_PAGE });
}ContributionsPage.contributore2e/pages/info/contributions-page.ts:17
No JSDoc
contributor (name: string ) {
return this .page.getByText (name);
}LinksPage.gotoe2e/pages/info/links-page.ts:13
No JSDoc
async goto () {
await navigate ({ page: this .page, url: LINKS_PAGE });
}LinksPage.resourceLinke2e/pages/info/links-page.ts:17
No JSDoc
resourceLink (title: string ) {
return this .page.getByRole ("link" , { name: title });
}ScannerPage.gotoe2e/pages/scanner/scanner-page.ts:52
async goto () {
await this .page.addInitScript (
([key]) => localStorage.setItem (key, JSON .stringify ({ webgpu: false })),
[SETTINGS_STORAGE_KEY ],
);
await navigate ({ page: this .page, url: SCANNER_PAGE });
}ScannerPage.locators.startCaptureButtone2e/pages/scanner/scanner-page.ts:22
No JSDoc
page.getByRole ("button" , { name: "Start capture" }) WeaponBuildsPagee2e/pages/builds/weapon-builds-page.ts:7
No JSDoc
FaqPagee2e/pages/info/faq-page.ts:6
SupportPagee2e/pages/info/support-page.ts:6
ContributionsPagee2e/pages/info/contributions-page.ts:6
LinksPagee2e/pages/info/links-page.ts:6
ScannerPagee2e/pages/scanner/scanner-page.ts:13
WeaponBuildsPage.gotoe2e/pages/builds/weapon-builds-page.ts:24
No JSDoc
async goto (weaponSlug: string ) {
await navigate ({ page: this .page, url: weaponBuildPage (weaponSlug) });
}TopRightButtons.locators.searchButtone2e/pages/layout/top-right-buttons.ts:16
No JSDoc
page
.getByRole ("banner" )
.getByRole ("button" , { name: "Search" }) LogInPopover.locators.logInButtone2e/pages/layout/log-in-popover.ts:9
No JSDoc
page.getByTestId ("log-in-popover-button" ) TopRightButtonse2e/pages/layout/top-right-buttons.ts:4
LogInPopovere2e/pages/layout/log-in-popover.ts:4
ArticlesPage.gotoe2e/pages/articles/articles-page.ts:14
No JSDoc
async goto () {
await navigate ({ page: this .page, url: ARTICLES_MAIN_PAGE });
}ArticlesPage.openArticlee2e/pages/articles/articles-page.ts:22
No JSDoc
async openArticle (title: string ) {
await this .articleLink (title).click ();
return new ArticlePage (this .page);
}ArticlePage.headinge2e/pages/articles/article-page.ts:17
No JSDoc
heading (title: string ) {
// the markdown body repeats the title as its own h1, the page h1 comes first
return this .page.getByRole ("heading" , { level: 1 , name: title }).first ();
}ArticlePage.authorLinke2e/pages/articles/article-page.ts:22
No JSDoc
authorLink (name: string ) {
return this .page
.getByRole ("link" , { name })
.and (this .page.locator ('[href^="/u/"]' ));
}ArticlePage.gotoe2e/pages/articles/article-page.ts:13
No JSDoc
async goto (slug: string ) {
await navigate ({ page: this .page, url: articlePage (slug) });
}ArticlePage.texte2e/pages/articles/article-page.ts:28
No JSDoc
text (content: string ) {
return this .page.getByText (content);
}ArticlesPagee2e/pages/articles/articles-page.ts:7
ArticlePagee2e/pages/articles/article-page.ts:6
ErrorPage.gotoe2e/pages/layout/error-page.ts:19
No JSDoc
async goto (url: string ) {
await navigate ({ page: this .page, url });
}ErrorPage.locators.roote2e/pages/layout/error-page.ts:12
No JSDoc
page.getByTestId ("error-page" ) ErrorPage.locators.notFoundHeadinge2e/pages/layout/error-page.ts:13
No JSDoc
page.getByRole ("heading" , {
name: "Error 404 - Page not found" ,
}) ErrorPage.responseStatuse2e/pages/layout/error-page.ts:23
No JSDoc
async responseStatus (url: string ) {
const response = await this .page.request.get (url);
return response.status ();
}CalendarPage.fetchICalFeede2e/pages/calendar/calendar-page.ts:100
async fetchICalFeed () {
const url = new URL (calendarIcalFeed ());
const response = await this .page.request.get (url.pathname + url.search);
return { status: response.status (), body: await response.text () };
}ErrorPagee2e/pages/layout/error-page.ts:5
FrontPage.openWelcomeBannere2e/pages/front-page/front-page.ts:23
No JSDoc
async openWelcomeBanner () {
await this .locators.welcomeBanner.click ();
return new WelcomePage (this .page);
}WelcomePage.locators.headinge2e/pages/user/welcome-page.ts:13
No JSDoc
page.getByRole ("heading" , {
name: "Introduction to competitive Splatoon and sendou.ink" ,
}) WelcomePagee2e/pages/user/welcome-page.ts:6