Skip to content

Admin · E2E tests

0 modules · 0 exports · 3 repositories · 5 e2e tests · 2 routes

  • SSendou
  • Users a test creates itself are coloured per test
  • Arrange data setup
  • Act what the user does
  • Assert what is expected

Admin panel

grants roles, friend code and API access to a user

targetSendouadmin.spec.ts:38

Renders/admin/api/art/new/vods/new

Setup
Arrange
  1. Create user ...ROLE_TARGET friend code null → target
    const target = await factories.UserFactory.create({
    	...ROLE_TARGET,
    	friendCode: null,
    });
Ttarget
Api page
Act
  1. Open the api page
    await api.goto();
Assert
  1. no access message is visible
    await expect(api.locators.noAccessMessage).toBeVisible();
SSendou
Admin actions page
Act
  1. Open the admin actions page
    await adminActions.goto();
  2. Update friend code ROLE_TARGET.discordName, “0123-4567-8901”
    await adminActions.updateFriendCode(ROLE_TARGET.discordName, FRIEND_CODE);
  3. Give artist ROLE_TARGET.discordName
    await adminActions.giveArtist(ROLE_TARGET.discordName);
  4. Give video adder ROLE_TARGET.discordName
    await adminActions.giveVideoAdder(ROLE_TARGET.discordName);
  5. Give api access ROLE_TARGET.discordName
    await adminActions.giveApiAccess(ROLE_TARGET.discordName);
  6. Open friend code look up
    await adminActions.openFriendCodeLookUp();
  7. Search friend code “0123-4567-8901”
    await adminActions.searchFriendCode(FRIEND_CODE);
Assert
  1. found user link ROLE_TARGET.discordName is visible
    await expect(
    	adminActions.foundUserLink(ROLE_TARGET.discordName),
    ).toBeVisible();
Ttarget
New art page
Act
  1. Open the new art page
    await newArt.goto();
Assert
  1. description input is visible
    await expect(newArt.locators.descriptionInput).toBeVisible();
New vod page
Act
  1. Open the new vod page
    await newVod.goto();
Assert
  1. add match button is visible
    await expect(newVod.locators.addMatchButton).toBeVisible();
Api page
Act
  1. Open the api page
    await api.goto();
Assert
  1. no access message is not visible
    await isNotVisible(api.locators.noAccessMessage);
Act
  1. Generate token “read” → token
    const token = await api.generateToken("read");
Assert
  1. token.length is more than 0
    expect(token.length).toBeGreaterThan(0);
Source
test("grants roles, friend code and API access to a user", async ({
	page,
	factories,
}) => {
	const target = await factories.UserFactory.create({
		...ROLE_TARGET,
		friendCode: null,
	});

	const api = new ApiPage(page);

	await impersonate(page, target.id);
	await api.goto();
	await expect(api.locators.noAccessMessage).toBeVisible();

	await impersonate(page, ADMIN_ID);
	const adminActions = new AdminActionsPage(page);
	await adminActions.goto();
	await adminActions.updateFriendCode(ROLE_TARGET.discordName, FRIEND_CODE);
	await adminActions.giveArtist(ROLE_TARGET.discordName);
	await adminActions.giveVideoAdder(ROLE_TARGET.discordName);
	await adminActions.giveApiAccess(ROLE_TARGET.discordName);

	await adminActions.openFriendCodeLookUp();
	await adminActions.searchFriendCode(FRIEND_CODE);
	await expect(
		adminActions.foundUserLink(ROLE_TARGET.discordName),
	).toBeVisible();

	await impersonate(page, target.id);

	const newArt = new NewArtPage(page);
	await newArt.goto();
	await expect(newArt.locators.descriptionInput).toBeVisible();

	const newVod = new NewVodPage(page);
	await newVod.goto();
	await expect(newVod.locators.addMatchButton).toBeVisible();

	await api.goto();
	await isNotVisible(api.locators.noAccessMessage);
	const token = await api.generateToken("read");
	expect(token.length).toBeGreaterThan(0);
})

grants tournament organizer role and patron status to a user

targetSendouadmin.spec.ts:83

Renders//admin/org/new

Setup
Arrange
  1. Create user ROLE_TARGET → target
    const target = await factories.UserFactory.create(ROLE_TARGET);
Ttarget
New organization page
Act
  1. Open the new organization page
    await newOrganization.goto();
Assert
  1. no permissions alert is visible
    await expect(newOrganization.locators.noPermissionsAlert).toBeVisible();
Act
  1. Go to “/”
    await navigate({ page, url: "/" });
Top right buttons
Assert
  1. support link is visible
    await expect(topRightButtons.locators.supportLink).toBeVisible();
SSendou
Admin actions page
Act
  1. Open the admin actions page
    await adminActions.goto();
  2. Give tournament organizer ROLE_TARGET.discordName
    await adminActions.giveTournamentOrganizer(ROLE_TARGET.discordName);
  3. tier one so the tournament organizer grant above stays the only source of that role

    Force patron ROLE_TARGET.discordName, tier “Support” expires at addYears(new Date(), 1)
    await adminActions.forcePatron(ROLE_TARGET.discordName, {
    	tier: "Support",
    	expiresAt: addYears(new Date(), 1),
    });
Ttarget
New organization page
Act
  1. Open the new organization page
    await newOrganization.goto();
Assert
  1. heading is visible
    await expect(newOrganization.locators.heading).toBeVisible();
Act
  1. Go to “/”
    await navigate({ page, url: "/" });
Assert
  1. support link is not visible
    await isNotVisible(topRightButtons.locators.supportLink);
Source
test("grants tournament organizer role and patron status to a user", async ({
	page,
	factories,
}) => {
	const target = await factories.UserFactory.create(ROLE_TARGET);

	const newOrganization = new NewOrganizationPage(page);
	const topRightButtons = new TopRightButtons(page);

	await impersonate(page, target.id);
	await newOrganization.goto();
	await expect(newOrganization.locators.noPermissionsAlert).toBeVisible();
	await navigate({ page, url: "/" });
	await expect(topRightButtons.locators.supportLink).toBeVisible();

	await impersonate(page, ADMIN_ID);
	const adminActions = new AdminActionsPage(page);
	await adminActions.goto();
	await adminActions.giveTournamentOrganizer(ROLE_TARGET.discordName);
	// tier one so the tournament organizer grant above stays the only source of that role
	await adminActions.forcePatron(ROLE_TARGET.discordName, {
		tier: "Support",
		expiresAt: addYears(new Date(), 1),
	});

	await impersonate(page, target.id);
	await newOrganization.goto();
	await expect(newOrganization.locators.heading).toBeVisible();

	await navigate({ page, url: "/" });
	await isNotVisible(topRightButtons.locators.supportLink);
})

Renders/admin/u/:identifier/u/:identifier/*

Setup
Arrange
  1. linking a player syncs XP badges, which requires every XP badge to exist

    For each value of SPLATOON_3_XP_BADGE_VALUES
    for (const value of SPLATOON_3_XP_BADGE_VALUES) {
    	await factories.BadgeFactory.create({ code: String(value) });
    }
    1. Create badge code String(value)
      await factories.BadgeFactory.create({ code: String(value) });
  2. Create X rank placement player spl id “e2e-unlinked-player” name “PlacedPlayer”
    await factories.XRankPlacementFactory.create({
    	playerSplId: "e2e-unlinked-player",
    	name: "PlacedPlayer",
    });
  3. Create user ...KEEPER → keeper
    const keeper = await factories.UserFactory.create({ ...KEEPER });
  4. Create user ...LEAVER
    await factories.UserFactory.create({ ...LEAVER });
  5. Create plus vote author Sendou voted id keeper.id
    await factories.PlusVoteFactory.create({
    	authorId: ADMIN_ID,
    	votedId: keeper.id,
    });
SSendou
Admin actions page
Act
  1. Open the admin actions page
    await adminActions.goto();
  2. Link player “N-ZAP”, 1
    await adminActions.linkPlayer("N-ZAP", LINKED_PLAYER_ID);
  3. Refresh plus tiers
    await adminActions.refreshPlusTiers();
  4. Migrate user old user name KEEPER.discordName new user name LEAVER.discordName
    await adminActions.migrateUser({
    	oldUserName: KEEPER.discordName,
    	newUserName: LEAVER.discordName,
    });
Assert
  1. user search suggestion KEEPER.discordName contains “+1”
    await expect(
    	await adminActions.userSearchSuggestion(KEEPER.discordName),
    ).toContainText("+1");
User page
Act
  1. Open the user page N-ZAP
    await userPage.goto(NZAP_TEST_ID);
Assert
  1. widget “x-rank-peaks” is visible
    await expect(userPage.widget("x-rank-peaks")).toBeVisible();
Act
  1. Open placements → playerPage
    const playerPage = await userPage.openPlacements();
Top search player page
Assert
  1. heading is visible
    await expect(playerPage.locators.heading).toBeVisible();
User page
Act
  1. the old user kept their account, now reached via the new user's Discord id

    Go to with identifier LEAVER.discordId
    await userPage.gotoWithIdentifier(LEAVER.discordId);
Assert
  1. username heading KEEPER.discordName is visible
    await expect(userPage.usernameHeading(KEEPER.discordName)).toBeVisible();
Source
test("links a player, refreshes plus tiers and migrates an account", async ({
	page,
	factories,
}) => {
	// linking a player syncs XP badges, which requires every XP badge to exist
	for (const value of SPLATOON_3_XP_BADGE_VALUES) {
		await factories.BadgeFactory.create({ code: String(value) });
	}
	await factories.XRankPlacementFactory.create({
		playerSplId: "e2e-unlinked-player",
		name: "PlacedPlayer",
	});
	const keeper = await factories.UserFactory.create({ ...KEEPER });
	await factories.UserFactory.create({ ...LEAVER });
	await factories.PlusVoteFactory.create({
		authorId: ADMIN_ID,
		votedId: keeper.id,
	});

	await impersonate(page, ADMIN_ID);
	const adminActions = new AdminActionsPage(page);
	await adminActions.goto();
	await adminActions.linkPlayer("N-ZAP", LINKED_PLAYER_ID);
	await adminActions.refreshPlusTiers();
	await adminActions.migrateUser({
		oldUserName: KEEPER.discordName,
		newUserName: LEAVER.discordName,
	});

	await expect(
		await adminActions.userSearchSuggestion(KEEPER.discordName),
	).toContainText("+1");

	const userPage = new UserPage(page);
	await userPage.goto(NZAP_TEST_ID);
	await expect(userPage.widget("x-rank-peaks")).toBeVisible();
	const playerPage = await userPage.openPlacements();
	await expect(playerPage.locators.heading).toBeVisible();

	// the old user kept their account, now reached via the new user's Discord id
	await userPage.gotoWithIdentifier(LEAVER.discordId);
	await expect(userPage.usernameHeading(KEEPER.discordName)).toBeVisible();
})

keeps the scroll position when an action shows a toast

Renders/admin

Setup
Arrange
  1. Create user ...ROLE_TARGET friend code null
    await factories.UserFactory.create({ ...ROLE_TARGET, friendCode: null });
SSendou
Admin actions page
Act
  1. Open the admin actions page
    await adminActions.goto();
  2. the form is far down the page, so filling it scrolls there

    Update friend code ROLE_TARGET.discordName, “0123-4567-8901”
    await adminActions.updateFriendCode(ROLE_TARGET.discordName, FRIEND_CODE);
Assert
  1. evaluate () => window.scrollY is more than 0
    expect(await page.evaluate(() => window.scrollY)).toBeGreaterThan(0);
Source
test("keeps the scroll position when an action shows a toast", async ({
	page,
	factories,
}) => {
	await factories.UserFactory.create({ ...ROLE_TARGET, friendCode: null });

	await impersonate(page, ADMIN_ID);
	const adminActions = new AdminActionsPage(page);
	await adminActions.goto();

	// the form is far down the page, so filling it scrolls there
	await adminActions.updateFriendCode(ROLE_TARGET.discordName, FRIEND_CODE);

	expect(await page.evaluate(() => window.scrollY)).toBeGreaterThan(0);
})

adds and deletes an external stream

Renders/admin/streams

SSendou
Admin streams page
Act
  1. Open the admin streams page
    await streams.goto();
Assert
  1. add stream heading is visible
    await expect(streams.locators.addStreamHeading).toBeVisible();
  2. no streams is visible
    await expect(streams.locators.noStreams).toBeVisible();
Act
  1. Create stream name “E2E Stream” url “https://www.twitch.tv/sendou” start time addHours(new Date(), 1) logo path TEST_IMAGE_PATH
    await streams.createStream({
    	name: "E2E Stream",
    	url: "https://www.twitch.tv/sendou",
    	startTime: addHours(new Date(), 1),
    	logoPath: TEST_IMAGE_PATH,
    });
Assert
  1. stream link “E2E Stream” is visible
    await expect(streams.streamLink("E2E Stream")).toBeVisible();
  2. no streams is not visible
    await isNotVisible(streams.locators.noStreams);
Act
  1. Delete stream “E2E Stream”
    await streams.deleteStream("E2E Stream");
Assert
  1. no streams is visible
    await expect(streams.locators.noStreams).toBeVisible();
Source
test("adds and deletes an external stream", async ({ page }) => {
	await impersonate(page, ADMIN_ID);

	const streams = new AdminStreamsPage(page);
	await streams.goto();
	await expect(streams.locators.addStreamHeading).toBeVisible();
	await expect(streams.locators.noStreams).toBeVisible();

	await streams.createStream({
		name: "E2E Stream",
		url: "https://www.twitch.tv/sendou",
		startTime: addHours(new Date(), 1),
		logoPath: TEST_IMAGE_PATH,
	});

	await expect(streams.streamLink("E2E Stream")).toBeVisible();
	await isNotVisible(streams.locators.noStreams);

	await streams.deleteStream("E2E Stream");
	await expect(streams.locators.noStreams).toBeVisible();
})