test(e2e): test login page
This commit is contained in:
parent
99601eaeb7
commit
11d98e63ae
10 changed files with 60 additions and 5 deletions
5
.env.test
Normal file
5
.env.test
Normal file
|
@ -0,0 +1,5 @@
|
|||
AUTH_SECRET="auth_secret"
|
||||
AUTH_URL="http://localhost:3000"
|
||||
DATABASE_URL="file:./dev.db"
|
||||
AUTH_AUTHENTIK_ID="id"
|
||||
AUTH_AUTHENTIK_ISSUER="issuer"
|
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
|
@ -23,5 +23,5 @@ jobs:
|
|||
uses: https://github.com/cypress-io/github-action@v6
|
||||
with:
|
||||
build: yarn run build
|
||||
start: yarn start
|
||||
start: yarn cypress:start_server
|
||||
component: true
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -33,6 +33,7 @@ yarn-error.log*
|
|||
# env files (can opt-in for committing if needed)
|
||||
.env*
|
||||
!.env.example
|
||||
!.env.test
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
|
|
@ -7,4 +7,10 @@ export default defineConfig({
|
|||
bundler: 'webpack',
|
||||
},
|
||||
},
|
||||
|
||||
e2e: {
|
||||
setupNodeEvents(on, config) {
|
||||
// implement node event listeners here
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
31
cypress/e2e/login.cy.ts
Normal file
31
cypress/e2e/login.cy.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
describe('login', () => {
|
||||
it('loads', () => {
|
||||
cy.visit('http://localhost:3000/');
|
||||
|
||||
cy.getBySel('login-header').should('exist');
|
||||
});
|
||||
|
||||
it('shows login form', () => {
|
||||
cy.visit('http://localhost:3000/');
|
||||
|
||||
cy.getBySel('login-form').should('exist');
|
||||
cy.getBySel('email-input').should('exist');
|
||||
cy.getBySel('password-input').should('exist');
|
||||
cy.getBySel('login-button').should('exist');
|
||||
});
|
||||
|
||||
it('shows sso button', () => {
|
||||
cy.visit('http://localhost:3000/');
|
||||
|
||||
cy.getBySel('sso-login-button_authentik').should('exist');
|
||||
});
|
||||
|
||||
it('allows login', () => {
|
||||
cy.visit('http://localhost:3000/');
|
||||
|
||||
cy.getBySel('email-input').type('test@example.com');
|
||||
cy.getBySel('password-input').type('password');
|
||||
cy.getBySel('login-button').click();
|
||||
cy.url().should('include', '/home');
|
||||
});
|
||||
});
|
|
@ -8,6 +8,7 @@
|
|||
"start": "node .next/standalone/server.js",
|
||||
"lint": "next lint",
|
||||
"format": "prettier --write .",
|
||||
"cypress:start_server": "cp .next/static/ .next/standalone/.next/ -r && dotenv -e .env.test -- node .next/standalone/server.js",
|
||||
"cypress:open": "cypress open",
|
||||
"cypress:run": "cypress run",
|
||||
"prisma:migrate": "dotenv -e .env.local -- prisma migrate dev",
|
||||
|
|
|
@ -30,7 +30,9 @@ export default async function LoginPage() {
|
|||
<div>
|
||||
<Card className='w-[350px] max-w-screen'>
|
||||
<CardHeader>
|
||||
<CardTitle className='text-lg text-center'>Login</CardTitle>
|
||||
<CardTitle className='text-lg text-center' data-cy='login-header'>
|
||||
Login
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className='gap-6 flex flex-col'>
|
||||
<LoginForm />
|
||||
|
@ -42,6 +44,7 @@ export default async function LoginPage() {
|
|||
key={provider.id}
|
||||
provider={provider.id}
|
||||
providerDisplayName={provider.name}
|
||||
data-cy={'sso-login-button_' + provider.name.toLowerCase()}
|
||||
/>
|
||||
))}
|
||||
</CardContent>
|
||||
|
|
|
@ -7,13 +7,14 @@ export default function LabeledInput({
|
|||
placeholder,
|
||||
value,
|
||||
name,
|
||||
...props
|
||||
}: {
|
||||
type: 'text' | 'email' | 'password';
|
||||
label: string;
|
||||
placeholder?: string;
|
||||
name: string;
|
||||
value?: string;
|
||||
name?: string;
|
||||
}) {
|
||||
} & React.InputHTMLAttributes<HTMLInputElement>) {
|
||||
return (
|
||||
<div className='flex flex-col gap-1'>
|
||||
<Label htmlFor={name}>{label}</Label>
|
||||
|
@ -24,6 +25,7 @@ export default function LabeledInput({
|
|||
defaultValue={value}
|
||||
id={name}
|
||||
name={name}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -10,6 +10,7 @@ export default function LoginForm() {
|
|||
return (
|
||||
<form
|
||||
className='flex flex-col gap-5 w-full'
|
||||
data-cy='login-form'
|
||||
action={async (formData) => {
|
||||
'use server';
|
||||
try {
|
||||
|
@ -27,17 +28,20 @@ export default function LoginForm() {
|
|||
label='E-Mail or Username'
|
||||
placeholder='What you are known as.'
|
||||
name='email'
|
||||
data-cy='email-input'
|
||||
/>
|
||||
<LabeledInput
|
||||
type='password'
|
||||
label='Password'
|
||||
placeholder="Let's hope you remember it."
|
||||
name='password'
|
||||
data-cy='password-input'
|
||||
/>
|
||||
<Button
|
||||
className='hover:bg-blue-600 hover:text-white'
|
||||
type='submit'
|
||||
variant='secondary'
|
||||
data-cy='login-button'
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
|
|
|
@ -5,10 +5,11 @@ import { faOpenid } from '@fortawesome/free-brands-svg-icons';
|
|||
export default function SSOLogin({
|
||||
provider,
|
||||
providerDisplayName,
|
||||
...props
|
||||
}: {
|
||||
provider: string;
|
||||
providerDisplayName: string;
|
||||
}) {
|
||||
} & React.HTMLProps<HTMLFormElement>) {
|
||||
return (
|
||||
<form
|
||||
className='flex flex-col items-center gap-4 w-full'
|
||||
|
@ -16,6 +17,7 @@ export default function SSOLogin({
|
|||
'use server';
|
||||
await signIn(provider);
|
||||
}}
|
||||
{...props}
|
||||
>
|
||||
<IconButton
|
||||
className='w-full'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue