Skip to content

Settings · E2E tests

0 modules · 0 exports · 0 repositories · 9 e2e tests · 1 route

  • SSendou
  • Arrange data setup
  • Act what the user does
  • Assert what is expected

Settings

updates 'disableBuildAbilitySorting'

Renders/builds/:slug/settings

Setup
Arrange
  1. Create build owner Sendou weapon spl ids 200 abilities UNSORTED_ABILITIES
    await factories.BuildFactory.create({
    	ownerId: ADMIN_ID,
    	weaponSplIds: [LUNA_BLASTER_ID],
    	abilities: UNSORTED_ABILITIES,
    });
SSendou
Weapon builds page
Act
  1. Open the weapon builds page “luna-blaster”
    await weaponBuilds.goto("luna-blaster");
  2. Inner HTML → oldContents
    const oldContents = await weaponBuilds.buildCard(0).root.innerHTML();
Settings page
Act
  1. Disable build ability sorting
    await settings.disableBuildAbilitySorting();
Weapon builds page
Act
  1. Open the weapon builds page “luna-blaster”
    await weaponBuilds.goto("luna-blaster");
  2. Inner HTML → newContents
    const newContents = await weaponBuilds.buildCard(0).root.innerHTML();
Assert
  1. newContents is not oldContents
    expect(newContents).not.toBe(oldContents);
Source
test("updates 'disableBuildAbilitySorting'", async ({ page, factories }) => {
	await factories.BuildFactory.create({
		ownerId: ADMIN_ID,
		weaponSplIds: [LUNA_BLASTER_ID],
		abilities: UNSORTED_ABILITIES,
	});

	await impersonate(page);

	const weaponBuilds = new WeaponBuildsPage(page);
	await weaponBuilds.goto("luna-blaster");

	const oldContents = await weaponBuilds.buildCard(0).root.innerHTML();

	const settings = new SettingsPage(page);
	await settings.disableBuildAbilitySorting();

	await weaponBuilds.goto("luna-blaster");

	const newContents = await weaponBuilds.buildCard(0).root.innerHTML();

	expect(newContents).not.toBe(oldContents);
})

updates clock format preference

Renders/calendar/settings

Setup
Arrange
  1. the clock header only renders above a day's events

    Create calendar event author Sendou
    await factories.CalendarEventFactory.create({ authorId: ADMIN_ID });
SSendou
Calendar page
Act
  1. Open the calendar page
    await calendar.goto();
  2. First → clockTime
    const clockTime = calendar.locators.clockHeaderTimes.first();
  3. Text content → initialTime
    const initialTime = await clockTime.textContent();
Assert
  1. initialTime match /AM|PM/
    expect(initialTime).toMatch(/AM|PM/);
Settings page
Act
  1. Set clock format “24h”
    await settings.setClockFormat("24h");
Calendar page
Act
  1. Open the calendar page
    await calendar.goto();
  2. Text content → newTime
    const newTime = await clockTime.textContent();
Assert
  1. newTime not match /AM|PM/
    expect(newTime).not.toMatch(/AM|PM/);
  2. newTime is not initialTime
    expect(newTime).not.toBe(initialTime);
  3. newTime contains “:”
    expect(newTime).toContain(":");
Source
test("updates clock format preference", async ({ page, factories }) => {
	// the clock header only renders above a day's events
	await factories.CalendarEventFactory.create({ authorId: ADMIN_ID });

	await impersonate(page);

	const calendar = new CalendarPage(page);
	await calendar.goto();

	const clockTime = calendar.locators.clockHeaderTimes.first();
	const initialTime = await clockTime.textContent();

	expect(initialTime).toMatch(/AM|PM/);

	const settings = new SettingsPage(page);
	await settings.setClockFormat("24h");

	await calendar.goto();

	const newTime = await clockTime.textContent();

	expect(newTime).not.toMatch(/AM|PM/);
	expect(newTime).not.toBe(initialTime);
	expect(newTime).toContain(":");
})

switches language to Japanese, persists it across pages and restores English

Renders/faq/settings

LOLogged out
Settings page
Act
  1. Open the settings page “locale”
    await settings.goto("locale");
Assert
  1. page heading reads “Settings”
    await expect(settings.locators.pageHeading).toHaveText("Settings");
Act
  1. Select language “日本語”
    await settings.selectLanguage("日本語");
Assert
  1. page heading reads “設定”
    await expect(settings.locators.pageHeading).toHaveText("設定");
Faq page
Act
  1. full page load without the lng param -> the language comes from the cookie; the faq namespace is registered via the route handle

    Open the faq page
    await faq.goto();
Assert
  1. question “プラスサーバーとはなんですか?” is visible
    await expect(faq.question("プラスサーバーとはなんですか?")).toBeVisible();
Settings page
Act
  1. Open the settings page “locale”
    await settings.goto("locale");
Assert
  1. page heading reads “設定”
    await expect(settings.locators.pageHeading).toHaveText("設定");
Act
  1. Select language “English”
    await settings.selectLanguage("English");
Assert
  1. page heading reads “Settings”
    await expect(settings.locators.pageHeading).toHaveText("Settings");
Faq page
Act
  1. Open the faq page
    await faq.goto();
Assert
  1. question “What is the Plus Server?” is visible
    await expect(faq.question("What is the Plus Server?")).toBeVisible();
Source
test("switches language to Japanese, persists it across pages and restores English", async ({
	page,
}) => {
	const settings = new SettingsPage(page);
	const faq = new FaqPage(page);

	await settings.goto("locale");
	await expect(settings.locators.pageHeading).toHaveText("Settings");

	await settings.selectLanguage("日本語");
	await expect(settings.locators.pageHeading).toHaveText("設定");

	// full page load without the lng param -> the language comes from the cookie;
	// the faq namespace is registered via the route handle
	await faq.goto();
	await expect(faq.question("プラスサーバーとはなんですか?")).toBeVisible();

	await settings.goto("locale");
	await expect(settings.locators.pageHeading).toHaveText("設定");

	await settings.selectLanguage("English");
	await expect(settings.locators.pageHeading).toHaveText("Settings");

	await faq.goto();
	await expect(faq.question("What is the Plus Server?")).toBeVisible();
})

shows in-game names in the picked game language and the rest in the site's language

Renders/builds/:slug/settings

Setup
Arrange
  1. Create build owner Sendou weapon spl ids 200
    await factories.BuildFactory.create({
    	ownerId: ADMIN_ID,
    	weaponSplIds: [LUNA_BLASTER_ID],
    });
LOLogged out
Settings page
Act
  1. Open the settings page “locale”
    await settings.goto("locale");
  2. Select game language “日本語”
    await settings.selectGameLanguage("日本語");
Weapon builds page
Act
  1. Open the weapon builds page “luna-blaster”
    await weaponBuilds.goto("luna-blaster");
Assert
  1. weapon image “ノヴァブラスター” is visible
    await expect(
    	weaponBuilds.buildCard(0).weaponImage("ノヴァブラスター"),
    ).toBeVisible();
  2. ability stats tab is visible
    await expect(weaponBuilds.locators.abilityStatsTab).toBeVisible();
Source
test("shows in-game names in the picked game language and the rest in the site's language", async ({
	page,
	factories,
}) => {
	await factories.BuildFactory.create({
		ownerId: ADMIN_ID,
		weaponSplIds: [LUNA_BLASTER_ID],
	});

	const settings = new SettingsPage(page);
	const weaponBuilds = new WeaponBuildsPage(page);

	await settings.goto("locale");
	await settings.selectGameLanguage("日本語");

	await weaponBuilds.goto("luna-blaster");
	await expect(
		weaponBuilds.buildCard(0).weaponImage("ノヴァブラスター"),
	).toBeVisible();
	await expect(weaponBuilds.locators.abilityStatsTab).toBeVisible();
})

persists sound settings and dark/light theme across reload

Renders/settings

SSendou
Settings page
Act
  1. Open the settings page “sounds”
    await settings.goto("sounds");
  2. Sound checkbox “Group invitation received” → likeSound
    const likeSound = settings.soundCheckbox("Group invitation received");
Assert
  1. likeSound is checked
    await expect(likeSound).toBeChecked();
Act
  1. Click likeSound
    await likeSound.click();
Assert
  1. likeSound is not checked
    await expect(likeSound).not.toBeChecked();
Act
  1. Set sound volume “37”
    await settings.setSoundVolume("37");
  2. default resolves to light (auto + light color scheme) so dark is a real change

    Open the settings page “theme”
    await settings.goto("theme");
  3. Set theme “Dark”
    await settings.setTheme("Dark");
Assert
  1. html root has class /dark/
    await expect(settings.locators.htmlRoot).toHaveClass(/dark/);
Act
  1. Reload
    await settings.reload();
Assert
  1. html root has class /dark/
    await expect(settings.locators.htmlRoot).toHaveClass(/dark/);
Act
  1. Open the settings page “sounds”
    await settings.goto("sounds");
Assert
  1. likeSound is not checked
    await expect(likeSound).not.toBeChecked();
  2. volume slider has value “37”
    await expect(settings.locators.volumeSlider).toHaveValue("37");
Act
  1. Open the settings page “theme”
    await settings.goto("theme");
  2. Set theme “Light”
    await settings.setTheme("Light");
Assert
  1. html root has class /light/
    await expect(settings.locators.htmlRoot).toHaveClass(/light/);
  2. html root does not have class /dark/
    await expect(settings.locators.htmlRoot).not.toHaveClass(/dark/);
Source
test("persists sound settings and dark/light theme across reload", async ({
	page,
}) => {
	await impersonate(page);

	const settings = new SettingsPage(page);
	await settings.goto("sounds");

	const likeSound = settings.soundCheckbox("Group invitation received");
	await expect(likeSound).toBeChecked();
	await likeSound.click();
	await expect(likeSound).not.toBeChecked();
	await settings.setSoundVolume("37");

	// default resolves to light (auto + light color scheme) so dark is a real change
	await settings.goto("theme");
	await settings.setTheme("Dark");
	await expect(settings.locators.htmlRoot).toHaveClass(/dark/);

	await settings.reload();
	await expect(settings.locators.htmlRoot).toHaveClass(/dark/);

	await settings.goto("sounds");
	await expect(likeSound).not.toBeChecked();
	await expect(settings.locators.volumeSlider).toHaveValue("37");

	await settings.goto("theme");
	await settings.setTheme("Light");
	await expect(settings.locators.htmlRoot).toHaveClass(/light/);
	await expect(settings.locators.htmlRoot).not.toHaveClass(/dark/);
})

Match profile map preferences

retains map selection when toggling a mode prefer -> avoid -> prefer

Renders/settings

SSendou
Match profile page
Act
  1. Open the match profile page
    await matchProfile.goto();
  2. Set mode preference “SZ”, “Prefer”
    await matchProfile.maps.setModePreference("SZ", "Prefer");
  3. Select mode tab “SZ”
    await matchProfile.maps.selectModeTab("SZ");
  4. Click map button “SZ”, 1
    await matchProfile.maps.mapButton("SZ", 1).click();
Assert
  1. map button “SZ”, 1 has class SELECTED_MAP_CLASS
    await expect(matchProfile.maps.mapButton("SZ", 1)).toHaveClass(
    	SELECTED_MAP_CLASS,
    );
Act
  1. avoiding hides the picker, but the selection should be remembered

    Set mode preference “SZ”, “Avoid”
    await matchProfile.maps.setModePreference("SZ", "Avoid");
Assert
  1. map button “SZ”, 1 is not visible
    await isNotVisible(matchProfile.maps.mapButton("SZ", 1));
Act
  1. Set mode preference “SZ”, “Prefer”
    await matchProfile.maps.setModePreference("SZ", "Prefer");
  2. Select mode tab “SZ”
    await matchProfile.maps.selectModeTab("SZ");
Assert
  1. map button “SZ”, 1 has class SELECTED_MAP_CLASS
    await expect(matchProfile.maps.mapButton("SZ", 1)).toHaveClass(
    	SELECTED_MAP_CLASS,
    );
Source
test("retains map selection when toggling a mode prefer -> avoid -> prefer", async ({
	page,
}) => {
	await impersonate(page);

	const matchProfile = new MatchProfilePage(page);
	await matchProfile.goto();

	await matchProfile.maps.setModePreference("SZ", "Prefer");
	await matchProfile.maps.selectModeTab("SZ");
	await matchProfile.maps.mapButton("SZ", 1).click();
	await expect(matchProfile.maps.mapButton("SZ", 1)).toHaveClass(
		SELECTED_MAP_CLASS,
	);

	// avoiding hides the picker, but the selection should be remembered
	await matchProfile.maps.setModePreference("SZ", "Avoid");
	await isNotVisible(matchProfile.maps.mapButton("SZ", 1));

	await matchProfile.maps.setModePreference("SZ", "Prefer");
	await matchProfile.maps.selectModeTab("SZ");
	await expect(matchProfile.maps.mapButton("SZ", 1)).toHaveClass(
		SELECTED_MAP_CLASS,
	);
})

can save 'zones only' after a now-avoided mode previously had a map pool

Renders/settings

SSendou
Match profile page
Act
  1. Open the match profile page
    await matchProfile.goto();
  2. stage 2 is not banned in TC

    Set mode preference “SZ”, “Prefer”
    await matchProfile.maps.setModePreference("SZ", "Prefer");
  3. Select mode tab “SZ”
    await matchProfile.maps.selectModeTab("SZ");
  4. Click map button “SZ”, 1
    await matchProfile.maps.mapButton("SZ", 1).click();
  5. Set mode preference “TC”, “Prefer”
    await matchProfile.maps.setModePreference("TC", "Prefer");
  6. Select mode tab “TC”
    await matchProfile.maps.selectModeTab("TC");
  7. Click map button “TC”, 2
    await matchProfile.maps.mapButton("TC", 2).click();
  8. Save
    await matchProfile.save();
  9. Set mode preference “TW”, “Avoid”
    await matchProfile.maps.setModePreference("TW", "Avoid");
  10. Set mode preference “TC”, “Avoid”
    await matchProfile.maps.setModePreference("TC", "Avoid");
  11. Set mode preference “RM”, “Avoid”
    await matchProfile.maps.setModePreference("RM", "Avoid");
  12. Set mode preference “CB”, “Avoid”
    await matchProfile.maps.setModePreference("CB", "Avoid");
  13. Save
    await matchProfile.save();
  14. the previously saved TC pool must not resurface as an invalid "pool for an avoided mode"

    Open the match profile page
    await matchProfile.goto();
  15. Save
    await matchProfile.save();
Assert
  1. avoided mode pool error is not visible
    await isNotVisible(matchProfile.locators.avoidedModePoolError);
Source
test("can save 'zones only' after a now-avoided mode previously had a map pool", async ({
	page,
}) => {
	await impersonate(page);

	const matchProfile = new MatchProfilePage(page);
	await matchProfile.goto();

	// stage 2 is not banned in TC
	await matchProfile.maps.setModePreference("SZ", "Prefer");
	await matchProfile.maps.selectModeTab("SZ");
	await matchProfile.maps.mapButton("SZ", 1).click();
	await matchProfile.maps.setModePreference("TC", "Prefer");
	await matchProfile.maps.selectModeTab("TC");
	await matchProfile.maps.mapButton("TC", 2).click();
	await matchProfile.save();

	await matchProfile.maps.setModePreference("TW", "Avoid");
	await matchProfile.maps.setModePreference("TC", "Avoid");
	await matchProfile.maps.setModePreference("RM", "Avoid");
	await matchProfile.maps.setModePreference("CB", "Avoid");
	await matchProfile.save();

	// the previously saved TC pool must not resurface as an invalid "pool for an avoided mode"
	await matchProfile.goto();

	await matchProfile.save();
	await isNotVisible(matchProfile.locators.avoidedModePoolError);
})

Spoiler-free mode

censors bracket and reveals on click

Renders/settings/to/:id/to/:id/brackets/to/:id/results

Setup
Arrange
  1. Create finalized tournament → tournament
    const tournament = await createFinalizedTournament(factories);
SSendou
Settings page
Act
  1. Enable spoiler free mode
    await settings.enableSpoilerFreeMode();
Tournament brackets page
Act
  1. Open the tournament brackets page tournament.id
    await brackets.goto(tournament.id);
Assert
  1. show results button is visible
    await expect(brackets.locators.showResultsButton).toBeVisible();
  2. first censored team names is visible
    await expect(brackets.locators.censoredTeamNames.first()).toBeVisible();
Act
  1. Click show results button
    await brackets.locators.showResultsButton.click();
Assert
  1. hide results button is visible
    await expect(brackets.locators.hideResultsButton).toBeVisible();
  2. censored team names is not visible
    await isNotVisible(brackets.locators.censoredTeamNames);
Tournament results page
Act
  1. Open the tournament results page tournament.id
    await results.goto(tournament.id);
Assert
  1. first result team names is visible
    await expect(results.locators.resultTeamNames.first()).toBeVisible();
Source
test("censors bracket and reveals on click", async ({ page, factories }) => {
	const tournament = await createFinalizedTournament(factories);

	await impersonate(page);
	const settings = new SettingsPage(page);
	await settings.enableSpoilerFreeMode();

	const brackets = new TournamentBracketsPage(page);
	await brackets.goto(tournament.id);

	await expect(brackets.locators.showResultsButton).toBeVisible();

	await expect(brackets.locators.censoredTeamNames.first()).toBeVisible();

	await brackets.locators.showResultsButton.click();

	await expect(brackets.locators.hideResultsButton).toBeVisible();
	await isNotVisible(brackets.locators.censoredTeamNames);

	// the sessionStorage reveal carries over to the results page
	const results = new TournamentResultsPage(page);
	await results.goto(tournament.id);
	await expect(results.locators.resultTeamNames.first()).toBeVisible();
})

results page is censored and can be revealed

Renders/settings/to/:id/to/:id/results

Setup
Arrange
  1. Create finalized tournament → tournament
    const tournament = await createFinalizedTournament(factories);
SSendou
Settings page
Act
  1. Enable spoiler free mode
    await settings.enableSpoilerFreeMode();
Tournament results page
Act
  1. Open the tournament results page tournament.id
    await results.goto(tournament.id);
Assert
  1. show results button is visible
    await expect(results.locators.showResultsButton).toBeVisible();
  2. result team names is not visible
    await isNotVisible(results.locators.resultTeamNames);
Act
  1. Click show results button
    await results.locators.showResultsButton.click();
Assert
  1. first result team names is visible
    await expect(results.locators.resultTeamNames.first()).toBeVisible();
Source
test("results page is censored and can be revealed", async ({
	page,
	factories,
}) => {
	const tournament = await createFinalizedTournament(factories);

	await impersonate(page);
	const settings = new SettingsPage(page);
	await settings.enableSpoilerFreeMode();

	const results = new TournamentResultsPage(page);
	await results.goto(tournament.id);

	await expect(results.locators.showResultsButton).toBeVisible();
	await isNotVisible(results.locators.resultTeamNames);

	await results.locators.showResultsButton.click();
	await expect(results.locators.resultTeamNames.first()).toBeVisible();
})