bemusic/bemuse

View on GitHub
e2e/tests/gameplay.spec.ts

Summary

Maintainability
A
35 mins
Test Coverage
import { Page, TestInfo, expect, test } from '@playwright/test'

test('Gameplay smoke test', async ({ page }, testInfo) => {
  await startBemuse(page)

  await test.step('Enter game', async () => {
    await takeScreenshot(page, testInfo, 'Title')
    await page.getByTestId('enter-game').click()
    await takeScreenshot(page, testInfo, 'Mode selection')
    await page.getByTestId('keyboard-mode').click()
    await takeScreenshot(page, testInfo, 'Song selection')
    await page.getByTestId('play-selected-chart').click()
    await expect(page.locator('.game-display canvas')).toBeVisible()
  })

  await test.step('Play through the game', async () => {
    await test.step('Press Enter to start the song', async () => {
      await page.waitForTimeout(100)
      await page.keyboard.down('Enter')
      await page.waitForTimeout(100)
      await page.keyboard.up('Enter')
    })

    const gameEvents = [
      { key: 'j', beat: 4, expectedScore: 69444 },
      { key: 'f', beat: 5, expectedScore: 138888 },
      { key: 'f', beat: 6, expectedScore: 208333 },
      { key: 'k', beat: 7, expectedScore: 277777 },
      { key: 'j', beat: 8, expectedScore: 347221 },
      { key: 'f', beat: 8.5, expectedScore: 416666 },
      { key: 'f', beat: 9, expectedScore: 486110 },
      { key: 'k', beat: 9.75, expectedScore: 524305 },
    ]
    for (const [i, { key, beat, expectedScore }] of gameEvents.entries()) {
      const t = (beat * 60) / 140
      const tString = t.toFixed(2)
      const n = i + 1
      const title = `Hit key ${key} at t=${tString} (note #${n}, expectedScore=${expectedScore})`
      await test.step(title, async () => {
        await page.evaluate(
          async ([t]) => {
            const anyWindow = window as any
            const BemuseTestMode = anyWindow.BemuseTestMode
            anyWindow.TEST_pausePromise = BemuseTestMode.pauseAt(t)
          },
          [t]
        )
        await page.evaluate(() => (window as any).TEST_pausePromise)
        await page.keyboard.down(key)
        await page.waitForTimeout(100)
        await page.keyboard.up(key)
        await expect
          .poll(async () =>
            page.evaluate(() => {
              const anyWindow = window as any
              const BemuseTestMode = anyWindow.BemuseTestMode
              return BemuseTestMode.getScore()
            })
          )
          .toBe(expectedScore)
      })
    }
  })

  await takeScreenshot(page, testInfo, 'Gameplay')
  await page.evaluate(() => {
    const anyWindow = window as any
    const BemuseTestMode = anyWindow.BemuseTestMode
    BemuseTestMode.unpause()
  })
  await expect(page.locator('.ResultScene')).toBeVisible()
  await expect(page.locator('.Rankingのyours')).toHaveText(/create an account/)
  await expect(page.locator('.Rankingのleaderboard')).toHaveText(/No Data/)

  await page.locator('.Rankingのyours').getByText('log in').click()
  await page
    .locator('.AuthenticationPanel')
    .getByRole('textbox', { name: 'Username' })
    .fill('Playwright')
  await page
    .locator('.AuthenticationPanel')
    .getByRole('textbox', { name: 'Password' })
    .fill('hunter2')
  await takeScreenshot(page, testInfo, 'Authentication')
  await page
    .locator('.AuthenticationPanel')
    .getByRole('button', { name: 'Log In' })
    .click()

  await expect(page.locator('.Rankingのyours')).toHaveText(/Playwright/)
  await expect(page.locator('.Rankingのleaderboard')).toHaveText(/Playwright/)

  await takeScreenshot(page, testInfo, 'Result')

  await page.getByText('Continue').first().click()
  await expect(page.getByTestId('stats-play-count')).toHaveText('1')
  await expect(page.getByTestId('stats-best-score')).toHaveText('524305')

  await page.getByText('Ranking').click()
  await expect(page.locator('.Ranking')).toContainText('524305')
})

test.skip('works offline', async ({ page }) => {
  await startBemuse(page)
  await expect
    .poll(() => page.evaluate(() => navigator.serviceWorker.controller?.state))
    .toBe('activated')
  await page.context().setOffline(true)
  const failures: string[] = []
  page.context().on('requestfailed', (r) => {
    const errorText = r.failure()!.errorText
    if (
      r.url().startsWith('http://localhost') &&
      errorText !== 'net::ERR_ABORTED'
    ) {
      failures.push(r.url() + ' ' + errorText)
    }
  })
  await page.reload()
  await page.getByTestId('enter-game').click()
  await expect(page.getByTestId('keyboard-mode')).toBeVisible()
  expect(failures).toHaveLength(0)
  await page.context().setOffline(false)
})

async function takeScreenshot(page: Page, testInfo: TestInfo, name: string) {
  await testInfo.attach(name, {
    body: await page.screenshot(),
    contentType: 'image/png',
  })
}

async function startBemuse(page: Page) {
  const testMusicServer =
    'https://raw.githubusercontent.com/bemusic/bemuse-test-server/master'
  const url = `/?server=${testMusicServer}&flags=fake-scoreboard`
  await page.goto(url)

  // Enter the test mode
  await expect
    .poll(
      async () =>
        page.evaluate(() => {
          const BemuseTestMode = (window as any).BemuseTestMode
          if (BemuseTestMode) {
            BemuseTestMode.enableTestMode()
            return true
          } else {
            return false
          }
        }),
      { timeout: 10000 }
    )
    .toBe(true)
}