### Recap
In [part I,](https://www.codingzeal.com/post/how-to-playwright) we learned how to setup and write our first test using playwright.
We'll continue on and setup a global config to save a user's session for writing more complex tests. For example; Our [Redwood Template App](https://github.com/CodingZeal/redwood-template-app) has user's with different roles. We would like to test the page functionally depending on what privileges a user has.
### Advance Configuration
In `playwright.config.ts` - `PlaywrightTestConfig` we are given the option to add a `globalSetup` pointing to the global setup file path. The file will run before all tests.
For example
```tsx
const config: PlaywrightTestConfig = {
globalSetup: require.resolve('./playwright.setup.ts')
...
}
```
In our case we decided to call the file `playwright.setup.ts`
`playwright.setup.ts`
```tsx
import { chromium } from '@playwright/test'
async function globalSetup() {
const URL = '<http://localhost:8910>'
const browser = await chromium.launch()
const adminLogin = await browser.newPage()
await adminLogin.goto(`${URL}/login`)
const usernameInput = adminLogin.getByLabel('username')
await usernameInput.click()
await usernameInput.fill('admin@example.com')
const passwordInput = adminLogin.getByLabel('password')
await passwordInput.click()
await passwordInput.fill('password')
await adminLogin.getByRole('button', { name: 'Login' }).click()
await adminLogin.waitForURL(URL, { waitUntil: 'domcontentloaded' })
await adminLogin
.context()
.storageState({ path: 'web/tests/storage/adminUser-pw.json' })
await browser.close()
}
export default globalSetup
```
The `globalSetup` function opens a new chromium browser with `chromium.lanch()`
`browser.newPage()` open’s a new page; creates a new page in a new browser context.
Afterwards, we navigate to our App's login page with `.goTo()`.
Then, we can use playwright's selectors to login as an admin user.
The part of the code we want to focus on is
```tsx
await adminLogin
.context()
.storageState({ path: 'web/tests/storage/adminUser-pw.json' })
```
`.context()` - Grabs the browsers contexts the page belongs to.
`.storageState()` - Returns storage state containing browser context, cookie, and local storage snapshot. We can specify the `path` we want the file to be stored at.
For instance,
```json
{
"cookies": [
{
"name": "session",
"value": "U2FsdGVkX1+HySRVzUW0F7tQKDMxgBHhLetU+iVR+9TjR4YbXbJqeFxNVnTPD+VQvlGvKeTRmOjOuRXK1ubrMKxhShViotBQqtOEO2rIwhAvQ4JCPeqohq3Iuo/hBqjrSRZ5lXP3cvuTElXPIbDGsA==",
"domain": "localhost",
"path": "/",
"expires": 1705431528.960474,
"httpOnly": true,
"secure": false,
"sameSite": "Strict"
}
],
"origins": []
}
```
What this does for us, is keep a user’s session active when running test.
### Let’s write a test!
Now that we have a session being stored for an Admin user; we can access the stored state and use in our test.
For example,
```tsx
test.use({ storageState: 'web/tests/storage/adminUser-pw.json' })
```
In our test, we can also use `.beforeEach()` hook to execute some logic before each test runs.
For instance,
```tsx
test.beforeEach(async ({ page }) => {
await page.goto('/')
const admin = page.getByText('Admin').first()
expect(admin)
await admin.click()
await page.waitForURL('/admin/users')
})
```
In the `.beforeEach()` hook we are confirming the User is logged in and is an admin.
Once, confirmed we can get into the meat and potatoes of the test.
We first setup a `MOCK_USER` to populate the input fields in our test.
```jsx
const MOCK_USER = {
email: 'cereal@example.com',
name: 'SnapCracklePop',
nickname: 'waffleCrisp',
pronouns: 'cheerios',
}
```
Thereafter, we can test for Admin CRUD (Create, Read, Update, Delete) user functionality.
For instance, admins can create new users.
```tsx
test.describe('admin crud user', async () => {
test('admin creates a new user', async ({ page }) => {
const newUser = page.getByText('New User').first()
expect(newUser)
await newUser.click()
await page.waitForURL('/admin/users/new')
const emailInput = page.locator('input[name="email"]')
await emailInput.click()
await emailInput.fill(MOCK_USER.email)
const nameInput = page.locator('input[name="name"]')
await nameInput.click()await nameInput.fill(MOCK_USER.name)
const nicknameInput = page.locator('input[name="nickname"]')
await nicknameInput.click()
await nicknameInput.fill(MOCK_USER.nickname)
const pronounsInput = page.locator('input[name="pronouns"]')
await pronounsInput.click()
await pronounsInput.fill(MOCK_USER.pronouns)
await page.getByLabel('Active').check()
expect(page.getByLabel('Active').isChecked()).toBeTruthy()
const saveButton = page.getByRole('button', { name: 'Save' })
await saveButton.click()
await page.waitForURL('/admin/users')
const newUserToast = page.getByText('User created')
expect(newUserToast)
const newUserList = page.getByText(MOCK_USER.email)
expect(newUserList)
})
})
```
`.locator()` - method can be used to find elements on the page.
`.click()` - used to simulate a click on the page.
`.fill()` - focuses on an input elements and fills it in.
`.waitForURL()` - waits for page to navigation.
### Challenge
Now that you got the hang of writing tests, can you finish the rest of the test for Read, Update, Delete?
### Resources
Missed how to setup Playwright?
- [How to Playwright](https://www.notion.so/How-to-Playwright-94e9b11f212b4a42987d0788ea2ff869)
Want to checkout the repo?
- [Redwood Template App](https://github.com/CodingZeal/redwood-template-app)
Learn RedwoodJS?
- [Learn with Redwood](https://www.learnwithredwood.com/)
- [RedwoodJS](https://redwoodjs.com/)
Interested in Fullstack?
- [Exploring Javascript Fullstack](https://www.codingzeal.com/post/exploring-full-stack-javascript-from-a-diehard-ruby-on-rails-fan)
Photo by Joshua Aragon on Unsplash
Are you ready to build something brilliant? We're ready to help.