Skip to content

Commit

Permalink
refactor(tests): ⚡️ Add msw and mock authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
baptisteArno committed Feb 12, 2022
1 parent d19b26e commit b1f54b7
Show file tree
Hide file tree
Showing 15 changed files with 789 additions and 129 deletions.
2 changes: 2 additions & 0 deletions apps/builder/.env.local.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
NEXT_PUBLIC_AUTH_MOCKING=disabled

DATABASE_URL=postgresql://postgres:@localhost:5432/typebot

ENCRYPTION_SECRET=q3t6v9y$B&E)H@McQfTjWnZr4u7x!z%C #256-bits secret (can be generated here: https://www.allkeysgenerator.com/Random/Security-Encryption-Key-Generator.aspx)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ const IndeterminateCheckbox = React.forwardRef(
const resolvedRef: any = ref || defaultRef

return (
<Flex justify="center">
<Flex justify="center" data-testid="checkbox">
<Checkbox
ref={resolvedRef}
{...rest}
Expand Down
30 changes: 30 additions & 0 deletions apps/builder/mocks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { rest, setupWorker } from 'msw'
import { setupServer } from 'msw/node'

const handlers = () => [
rest.get('http://localhost:3000/api/auth/session', (req, res, ctx) => {
const authenticatedUser = JSON.parse(
typeof localStorage !== 'undefined'
? (localStorage.getItem('authenticatedUser') as string)
: '{"id":"proUser","name":"John Smith","email":"john@smith.com","emailVerified":null,"image":"https://avatars.githubusercontent.com/u/16015833?v=4","plan":"PRO","stripeId":null}'
)
return res(
ctx.json({
user: authenticatedUser,
expires: '2022-03-13T17:02:42.317Z',
})
)
}),
]

export const enableMocks = () => {
if (typeof window === 'undefined') {
const server = setupServer(...handlers())
server.listen()
} else {
const worker = setupWorker(...handlers())
worker.start({
onUnhandledRequest: 'bypass',
})
}
}
8 changes: 6 additions & 2 deletions apps/builder/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
"test": "dotenv -e ./playwright/.env -e .env.local -- yarn playwright test",
"test:open": "dotenv -e ./playwright/.env -e .env.local -v PWDEBUG=1 -- yarn playwright test"
},
"msw": {
"workerDirectory": "public"
},
"dependencies": {
"@chakra-ui/css-reset": "^1.1.1",
"@chakra-ui/react": "^1.8.1",
Expand Down Expand Up @@ -50,6 +53,7 @@
"micro": "^9.3.4",
"micro-cors": "^0.1.1",
"models": "*",
"msw": "^0.36.8",
"next": "^12.0.9",
"next-auth": "4.1.2",
"nodemailer": "^6.7.2",
Expand All @@ -69,10 +73,10 @@
"styled-components": "^5.3.3",
"svg-round-corners": "^0.3.0",
"swr": "^1.2.0",
"typebot-js": "2.0.21",
"use-debounce": "^7.0.1",
"use-immer": "^0.6.0",
"utils": "*",
"typebot-js": "2.0.21"
"utils": "*"
},
"devDependencies": {
"@playwright/test": "^1.18.1",
Expand Down
3 changes: 3 additions & 0 deletions apps/builder/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import { TypebotContext } from 'contexts/TypebotContext'
import { useRouter } from 'next/router'
import { KBarProvider } from 'kbar'
import { actions } from 'libs/kbar'
import { enableMocks } from 'mocks'

if (process.env.NEXT_PUBLIC_AUTH_MOCKING === 'enabled') enableMocks()

const App = ({ Component, pageProps }: AppProps) => {
useRouterProgressBar()
Expand Down
4 changes: 2 additions & 2 deletions apps/builder/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ const config: PlaywrightTestConfig = {
timeout: 5000,
},
retries: process.env.NO_RETRIES ? 0 : 2,
workers: process.env.CI ? 1 : undefined,
workers: process.env.CI ? 1 : 3,
reporter: 'html',
maxFailures: process.env.CI ? 10 : undefined,
use: {
actionTimeout: 0,
baseURL: process.env.PLAYWRIGHT_BUILDER_TEST_BASE_URL,
trace: 'on-first-retry',
storageState: path.join(__dirname, 'playwright/authenticatedState.json'),
storageState: path.join(__dirname, 'playwright/proUser.json'),
video: 'retain-on-failure',
locale: 'en-US',
},
Expand Down
6 changes: 2 additions & 4 deletions apps/builder/playwright/.env.example
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
PLAYWRIGHT_BUILDER_TEST_BASE_URL=http://localhost:3000
NEXT_PUBLIC_AUTH_MOCKING=enabled

# For auth
GITHUB_EMAIL=
GITHUB_PASSWORD=
PLAYWRIGHT_BUILDER_TEST_BASE_URL=http://localhost:3000

# SMTP Credentials (Generated on https://ethereal.email/)
SMTP_HOST=smtp.ethereal.email
Expand Down
14 changes: 14 additions & 0 deletions apps/builder/playwright/freeUser.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"cookies": [],
"origins": [
{
"origin": "http://localhost:3000",
"localStorage": [
{
"name": "authenticatedUser",
"value": "{\"id\":\"freeUser\",\"name\":\"John Smith\",\"email\":\"john@smith.fr\",\"emailVerified\":null,\"image\":\"https://avatars.githubusercontent.com/u/16015833?v=4\",\"plan\":\"FREE\",\"stripeId\":null}"
}
]
}
]
}
46 changes: 3 additions & 43 deletions apps/builder/playwright/global-setup.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,14 @@
import { chromium, FullConfig, Page } from '@playwright/test'
import { existsSync } from 'fs'
import {
getSignedInUser,
setupDatabase,
teardownDatabase,
} from './services/database'
import { FullConfig } from '@playwright/test'
import { setupDatabase, teardownDatabase } from './services/database'

// eslint-disable-next-line @typescript-eslint/no-var-requires
require('dotenv').config({ path: '.env' })

async function globalSetup(config: FullConfig) {
const { baseURL } = config.projects[0].use
if (!baseURL) throw new Error('baseURL is missing')
if (!process.env.GITHUB_EMAIL || !process.env.GITHUB_PASSWORD)
throw new Error(
'GITHUB_EMAIL or GITHUB_PASSWORD are missing in the environment. They are required to log in.'
)

await teardownDatabase()

const signedInUser = await getSignedInUser(process.env.GITHUB_EMAIL as string)
if (!signedInUser || !existsSync('./playwright/authenticatedState.json')) {
const browser = await chromium.launch()
const page = await browser.newPage()
await signIn(page)
await page.context().storageState({
path: './playwright/authenticatedState.json',
})
}

await setupDatabase(process.env.GITHUB_EMAIL as string)
}

const signIn = async (page: Page) => {
await page.goto(`${process.env.PLAYWRIGHT_BUILDER_TEST_BASE_URL}/signin`)
await page.click('text=Continue with GitHub')
await page.fill('input[name="login"]', process.env.GITHUB_EMAIL as string)
await page.fill(
'input[name="password"]',
process.env.GITHUB_PASSWORD as string
)
await page.press('input[name="password"]', 'Enter')
try {
await page.locator('text=Authorize baptisteArno').click({ timeout: 3000 })
} catch {
return
}
await page.waitForNavigation({
url: `${process.env.PLAYWRIGHT_BUILDER_TEST_BASE_URL}/typebots`,
})
await setupDatabase()
}

export default globalSetup
14 changes: 14 additions & 0 deletions apps/builder/playwright/proUser.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"cookies": [],
"origins": [
{
"origin": "http://localhost:3000",
"localStorage": [
{
"name": "authenticatedUser",
"value": "{\"id\":\"proUser\",\"name\":\"John Smith\",\"email\":\"john@smith.com\",\"emailVerified\":null,\"image\":\"https://avatars.githubusercontent.com/u/16015833?v=4\",\"plan\":\"PRO\",\"stripeId\":null}"
}
]
}
]
}
28 changes: 19 additions & 9 deletions apps/builder/playwright/services/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,25 @@ import { encrypt } from 'utils'
const prisma = new PrismaClient()

export const teardownDatabase = async () => {
await prisma.user.deleteMany()
await prisma.credentials.deleteMany()
await prisma.dashboardFolder.deleteMany()
return prisma.typebot.deleteMany()
}

export const setupDatabase = async (userEmail: string) => {
const createdUser = await getSignedInUser(userEmail)
if (!createdUser) throw new Error("Couldn't find user")
process.env.PLAYWRIGHT_USER_ID = createdUser.id
export const setupDatabase = async () => {
await createUsers()
return createCredentials()
}

export const createUsers = () =>
prisma.user.createMany({
data: [
{ id: 'freeUser', email: 'free-user@email.com', name: 'Free user' },
{ id: 'proUser', email: 'pro-user@email.com', name: 'Pro user' },
],
})

export const getSignedInUser = (email: string) =>
prisma.user.findFirst({ where: { email } })

Expand All @@ -44,7 +51,7 @@ export const createTypebots = async (partialTypebots: Partial<Typebot>[]) => {
export const createFolders = (partialFolders: Partial<DashboardFolder>[]) =>
prisma.dashboardFolder.createMany({
data: partialFolders.map((folder) => ({
ownerId: process.env.PLAYWRIGHT_USER_ID as string,
ownerId: 'proUser',
name: 'Folder #1',
...folder,
})),
Expand All @@ -63,7 +70,7 @@ const createCredentials = () => {
data: [
{
name: 'test2@gmail.com',
ownerId: process.env.PLAYWRIGHT_USER_ID as string,
ownerId: 'proUser',
type: CredentialsType.GOOGLE_SHEETS,
data: encryptedData,
iv,
Expand All @@ -75,10 +82,13 @@ const createCredentials = () => {
export const updateUser = (data: Partial<User>) =>
prisma.user.update({
data,
where: { id: process.env.PLAYWRIGHT_USER_ID as string },
where: {
id: 'proUser',
},
})

export const createResults = async ({ typebotId }: { typebotId: string }) => {
await prisma.result.deleteMany()
await prisma.result.createMany({
data: [
...Array.from(Array(200)).map((_, idx) => {
Expand Down Expand Up @@ -137,7 +147,7 @@ const parseTestTypebot = (partialTypebot: Partial<Typebot>): Typebot => ({
id: partialTypebot.id ?? 'typebot',
folderId: null,
name: 'My typebot',
ownerId: process.env.PLAYWRIGHT_USER_ID as string,
ownerId: 'proUser',
theme: defaultTheme,
settings: defaultSettings,
createdAt: new Date(),
Expand Down Expand Up @@ -198,7 +208,7 @@ export const importTypebotInDatabase = (
const typebot: any = {
...JSON.parse(readFileSync(path).toString()),
...updates,
ownerId: process.env.PLAYWRIGHT_USER_ID,
ownerId: 'proUser',
}
return prisma.typebot.create({
data: typebot,
Expand Down
52 changes: 0 additions & 52 deletions apps/builder/playwright/tests/account.spec.ts

This file was deleted.

8 changes: 4 additions & 4 deletions apps/builder/playwright/tests/results.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ test.describe('Results page', () => {
await deleteButtonInConfirmDialog(page).click()
await expect(page.locator('text=content199')).toBeHidden()
await expect(page.locator('text=content198')).toBeHidden()
await page.check(':nth-match(input[type="checkbox"], 1)', { force: true })
await page.click('[data-testid="checkbox"] >> nth=0')
await page.click('button:has-text("Delete198")')
await deleteButtonInConfirmDialog(page).click()
await expect(page.locator(':nth-match(tr, 2)')).toBeHidden()
Expand Down Expand Up @@ -75,7 +75,7 @@ test.describe('Results page', () => {
const { data } = parse(file)
validateExportSelection(data)

await page.check(':nth-match(input[type="checkbox"], 1)', { force: true })
await page.click('[data-testid="checkbox"] >> nth=0')
const [downloadAll] = await Promise.all([
page.waitForEvent('download'),
page.locator('button:has-text("Export200")').click(),
Expand All @@ -101,6 +101,6 @@ const validateExportAll = (data: unknown[]) => {
}

const selectFirstResults = async (page: Page) => {
await page.check(':nth-match(input[type="checkbox"], 2)', { force: true })
return page.check(':nth-match(input[type="checkbox"], 3)', { force: true })
await page.click('[data-testid="checkbox"] >> nth=1')
return page.click('[data-testid="checkbox"] >> nth=2')
}
Loading

3 comments on commit b1f54b7

@vercel
Copy link

@vercel vercel bot commented on b1f54b7 Feb 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

viewer-v2 – ./apps/viewer

typebot-viewer.vercel.app
viewer-v2-git-main-typebot-io.vercel.app
viewer-v2-typebot-io.vercel.app

@vercel
Copy link

@vercel vercel bot commented on b1f54b7 Feb 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

builder-v2 – ./apps/builder

builder-v2-typebot-io.vercel.app
next.typebot.io
builder-v2-git-main-typebot-io.vercel.app

@vercel
Copy link

@vercel vercel bot commented on b1f54b7 Feb 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

landing-page-v2 – ./apps/landing-page

landing-page-v2-typebot-io.vercel.app
landing-page-v2-jade.vercel.app
landing-page-v2-git-main-typebot-io.vercel.app

Please sign in to comment.