mirror of
https://github.com/wassname/Open-Assistant.git
synced 2026-07-03 17:10:10 +08:00
Merge pull request #266 from othrayte/website-e2e-tests
Website e2e tests
This commit is contained in:
@@ -22,4 +22,11 @@ export default defineConfig({
|
||||
getCompareSnapshotsPlugin(on, config);
|
||||
},
|
||||
},
|
||||
|
||||
env: {
|
||||
MAILDEV_PROTOCOL: "http",
|
||||
MAILDEV_HOST: "localhost",
|
||||
MAILDEV_SMTP_PORT: "1025",
|
||||
MAILDEV_API_PORT: "1080",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,10 +1,41 @@
|
||||
import { faker } from "@faker-js/faker";
|
||||
|
||||
describe("signin flow", () => {
|
||||
it("redirects to a confirmation page on submit of valid email address", () => {
|
||||
cy.visit("/auth/signin");
|
||||
cy.get(".chakra-input").type(`test@example.com`);
|
||||
cy.get(".chakra-stack > .chakra-button").click();
|
||||
cy.get('form[data-cy="signin-email"').within(() => {
|
||||
cy.get(".chakra-input").type(`test@example.com`);
|
||||
cy.get(".chakra-stack > .chakra-button").click();
|
||||
});
|
||||
cy.url().should("contain", "/auth/verify");
|
||||
});
|
||||
it("emails a login link to the user when signing in with email", () => {
|
||||
// Use random email to avoid possibility of tests passing just due to other tests or previous runs also causing emails to be sent
|
||||
const emailAddress = faker.internet.email();
|
||||
cy.log("emailAddress", emailAddress);
|
||||
cy.request("GET", "/api/auth/csrf")
|
||||
.then((response) => {
|
||||
const csrfToken = response.body.csrfToken;
|
||||
cy.request("POST", "/api/auth/signin/email", {
|
||||
callbackUrl: "/",
|
||||
email: emailAddress,
|
||||
csrfToken,
|
||||
json: "true",
|
||||
});
|
||||
})
|
||||
.then((response) => {
|
||||
cy.signInUsingEmailedLink(emailAddress).then(() => {
|
||||
cy.get('[data-cy="username"]').should("exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
it("shows the logged in users email address if logged in with email", () => {
|
||||
const emailAddress = "user@example.com";
|
||||
cy.signInWithEmail(emailAddress);
|
||||
// The user will only see the email address if the window is wide enough, not technically required as even when hidden this will find it in the page.
|
||||
cy.viewport(1920, 1000);
|
||||
cy.contains('[data-cy="username"]', emailAddress);
|
||||
});
|
||||
});
|
||||
|
||||
export {};
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { faker } from "@faker-js/faker";
|
||||
|
||||
describe("replying as the assistant", () => {
|
||||
it("completes the current task on submit and on request shows a new task", () => {
|
||||
cy.signInWithEmail("cypress@example.com");
|
||||
cy.visit("/create/assistant_reply");
|
||||
|
||||
cy.get('[data-cy="task-id"').then((taskIdElement) => {
|
||||
const taskId = taskIdElement.text();
|
||||
|
||||
const reply = faker.lorem.sentence();
|
||||
cy.log("reply", reply);
|
||||
cy.get('[data-cy="reply"').type(reply);
|
||||
|
||||
cy.get('[data-cy="submit"]').click();
|
||||
|
||||
cy.get('[data-cy="next-task"]').click();
|
||||
|
||||
cy.get('[data-cy="task-id"').should((taskIdElement) => {
|
||||
expect(taskIdElement.text()).not.to.eq(taskId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
export {};
|
||||
@@ -0,0 +1,26 @@
|
||||
import { faker } from "@faker-js/faker";
|
||||
|
||||
describe("replying as the prompter", () => {
|
||||
it("completes the current task on submit and on request shows a new task", () => {
|
||||
cy.signInWithEmail("cypress@example.com");
|
||||
cy.visit("/create/user_reply");
|
||||
|
||||
cy.get('[data-cy="task-id"').then((taskIdElement) => {
|
||||
const taskId = taskIdElement.text();
|
||||
|
||||
const reply = faker.lorem.sentence();
|
||||
cy.log("reply", reply);
|
||||
cy.get('[data-cy="reply"').type(reply);
|
||||
|
||||
cy.get('[data-cy="submit"]').click();
|
||||
|
||||
cy.get('[data-cy="next-task"]').click();
|
||||
|
||||
cy.get('[data-cy="task-id"').should((taskIdElement) => {
|
||||
expect(taskIdElement.text()).not.to.eq(taskId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
export {};
|
||||
@@ -0,0 +1,30 @@
|
||||
describe("ranking prompter replies", () => {
|
||||
it("completes the current task on submit and on request shows a new task", () => {
|
||||
cy.signInWithEmail("cypress@example.com");
|
||||
cy.visit("/evaluate/rank_user_replies");
|
||||
|
||||
cy.get('[data-cy="task-id"').then((taskIdElement) => {
|
||||
const taskId = taskIdElement.text();
|
||||
|
||||
// Rank an item using the keyboard so that the submit button is enabled
|
||||
cy.get('button[aria-roledescription="sortable"]')
|
||||
.first()
|
||||
.click()
|
||||
.type("{enter}")
|
||||
.wait(100)
|
||||
.type("{downArrow}")
|
||||
.wait(100)
|
||||
.type("{enter}");
|
||||
|
||||
cy.get('[data-cy="submit"]').click();
|
||||
|
||||
cy.get('[data-cy="next-task"]').click();
|
||||
|
||||
cy.get('[data-cy="task-id"').should((taskIdElement) => {
|
||||
expect(taskIdElement.text()).not.to.eq(taskId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
export {};
|
||||
@@ -0,0 +1,30 @@
|
||||
describe("ranking initial prompts", () => {
|
||||
it("completes the current task on submit and on request shows a new task", () => {
|
||||
cy.signInWithEmail("cypress@example.com");
|
||||
cy.visit("/evaluate/rank_initial_prompts");
|
||||
|
||||
cy.get('[data-cy="task-id"').then((taskIdElement) => {
|
||||
const taskId = taskIdElement.text();
|
||||
|
||||
// Rank an item using the keyboard so that the submit button is enabled
|
||||
cy.get('button[aria-roledescription="sortable"]')
|
||||
.first()
|
||||
.click()
|
||||
.type("{enter}")
|
||||
.wait(100)
|
||||
.type("{downArrow}")
|
||||
.wait(100)
|
||||
.type("{enter}");
|
||||
|
||||
cy.get('[data-cy="submit"]').click();
|
||||
|
||||
cy.get('[data-cy="next-task"]').click();
|
||||
|
||||
cy.get('[data-cy="task-id"').should((taskIdElement) => {
|
||||
expect(taskIdElement.text()).not.to.eq(taskId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
export {};
|
||||
@@ -0,0 +1,30 @@
|
||||
describe("ranking assistant replies", () => {
|
||||
it("completes the current task on submit and on request shows a new task", () => {
|
||||
cy.signInWithEmail("cypress@example.com");
|
||||
cy.visit("/evaluate/rank_assistant_replies");
|
||||
|
||||
cy.get('[data-cy="task-id"').then((taskIdElement) => {
|
||||
const taskId = taskIdElement.text();
|
||||
|
||||
// Rank an item using the keyboard so that the submit button is enabled
|
||||
cy.get('button[aria-roledescription="sortable"]')
|
||||
.first()
|
||||
.click()
|
||||
.type("{enter}")
|
||||
.wait(100)
|
||||
.type("{downArrow}")
|
||||
.wait(100)
|
||||
.type("{enter}");
|
||||
|
||||
cy.get('[data-cy="submit"]').click();
|
||||
|
||||
cy.get('[data-cy="next-task"]').click();
|
||||
|
||||
cy.get('[data-cy="task-id"').should((taskIdElement) => {
|
||||
expect(taskIdElement.text()).not.to.eq(taskId);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
export {};
|
||||
@@ -36,4 +36,38 @@
|
||||
// }
|
||||
// }
|
||||
|
||||
Cypress.Commands.add("signInUsingEmailedLink", (emailAddress) => {
|
||||
const mailDevApi = `${Cypress.env("MAILDEV_PROTOCOL")}://${Cypress.env(
|
||||
"MAILDEV_HOST"
|
||||
)}:${Cypress.env("MAILDEV_API_PORT")}`;
|
||||
cy.request(
|
||||
"GET",
|
||||
`${mailDevApi}/email?headers.to=${emailAddress.toLowerCase()}`
|
||||
).then((response) => {
|
||||
const emails = response.body;
|
||||
|
||||
// Find and use login link
|
||||
const loginLink = emails
|
||||
.pop()
|
||||
.html.match(/href="[^"]+(\/api\/auth\/callback\/[^"]+?)"/)[1];
|
||||
cy.visit(loginLink);
|
||||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add("signInWithEmail", (emailAddress) => {
|
||||
cy.request("GET", "/api/auth/csrf")
|
||||
.then((response) => {
|
||||
const csrfToken = response.body.csrfToken;
|
||||
cy.request("POST", "/api/auth/signin/email", {
|
||||
callbackUrl: "/",
|
||||
email: emailAddress,
|
||||
csrfToken,
|
||||
json: "true",
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
cy.signInUsingEmailedLink(emailAddress);
|
||||
});
|
||||
});
|
||||
|
||||
export {};
|
||||
|
||||
@@ -13,12 +13,8 @@
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import "./commands";
|
||||
import compareSnapshotCommand from "cypress-image-diff-js/dist/command";
|
||||
compareSnapshotCommand();
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
|
||||
export {};
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// load type definitions that come with Cypress module
|
||||
/// <reference types="cypress" />
|
||||
|
||||
declare global {
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
/**
|
||||
* Custom command to sign in with a given email address
|
||||
* @example cy.signInWithEmail('user@example.com')
|
||||
*/
|
||||
signInWithEmail(emailAddress: string): Chainable<Element>;
|
||||
|
||||
/**
|
||||
* Custom command to sign in with the link emailed to the given email address
|
||||
* @example cy.signInUsingEmailedLink('user@example.com')
|
||||
*/
|
||||
signInUsingEmailedLink(emailAddress: string): Chainable<Element>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
Generated
+17
@@ -44,6 +44,7 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.7",
|
||||
"@chakra-ui/storybook-addon": "^4.0.16",
|
||||
"@faker-js/faker": "^7.6.0",
|
||||
"@storybook/addon-actions": "^6.5.15",
|
||||
"@storybook/addon-essentials": "^6.5.15",
|
||||
"@storybook/addon-interactions": "^6.5.15",
|
||||
@@ -3591,6 +3592,16 @@
|
||||
"js-yaml": "bin/js-yaml.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@faker-js/faker": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-7.6.0.tgz",
|
||||
"integrity": "sha512-XK6BTq1NDMo9Xqw/YkYyGjSsg44fbNwYRx7QK2CuoQgyy+f1rrTDHoExVM5PsyXCtfl2vs2vVJ0MN0yN6LppRw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14.0.0",
|
||||
"npm": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@gar/promisify": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
|
||||
@@ -31099,6 +31110,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@faker-js/faker": {
|
||||
"version": "7.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-7.6.0.tgz",
|
||||
"integrity": "sha512-XK6BTq1NDMo9Xqw/YkYyGjSsg44fbNwYRx7QK2CuoQgyy+f1rrTDHoExVM5PsyXCtfl2vs2vVJ0MN0yN6LppRw==",
|
||||
"dev": true
|
||||
},
|
||||
"@gar/promisify": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.7",
|
||||
"@chakra-ui/storybook-addon": "^4.0.16",
|
||||
"@faker-js/faker": "^7.6.0",
|
||||
"@storybook/addon-actions": "^6.5.15",
|
||||
"@storybook/addon-essentials": "^6.5.15",
|
||||
"@storybook/addon-interactions": "^6.5.15",
|
||||
|
||||
@@ -34,7 +34,9 @@ export function UserMenu() {
|
||||
height="40"
|
||||
className="rounded-full"
|
||||
></Image>
|
||||
<p className="hidden lg:flex">{session.user.name || session.user.email}</p>
|
||||
<p data-cy="username" className="hidden lg:flex">
|
||||
{session.user.name || session.user.email}
|
||||
</p>
|
||||
</div>
|
||||
</Popover.Button>
|
||||
<AnimatePresence initial={false}>
|
||||
|
||||
@@ -2,7 +2,7 @@ export const TaskInfo = ({ id, output }: { id: string; output: string }) => {
|
||||
return (
|
||||
<div className="grid grid-cols-[min-content_auto] gap-x-2 text-gray-700">
|
||||
<b>Prompt</b>
|
||||
<span>{id}</span>
|
||||
<span data-cy="task-id">{id}</span>
|
||||
<b>Output</b>
|
||||
<span>{output}</span>
|
||||
</div>
|
||||
|
||||
@@ -41,7 +41,7 @@ export default function Signin({ csrfToken, providers }) {
|
||||
</form>
|
||||
)}
|
||||
{email && (
|
||||
<form onSubmit={signinWithEmail}>
|
||||
<form data-cy="signin-email" onSubmit={signinWithEmail}>
|
||||
<Stack>
|
||||
<Input variant="outline" size="lg" placeholder="Email Address" ref={emailEl} />
|
||||
<Button size={"lg"} leftIcon={<FaEnvelope />} colorScheme="gray" type="submit">
|
||||
|
||||
@@ -63,7 +63,7 @@ const AssistantReply = () => {
|
||||
<p className="text-lg py-1">Given the following conversation, provide an adequate reply</p>
|
||||
<Messages messages={task.conversation.messages} post_id={task.id} />
|
||||
</>
|
||||
<Textarea name="reply" placeholder="Reply..." ref={inputRef} />
|
||||
<Textarea name="reply" data-cy="reply" placeholder="Reply..." ref={inputRef} />
|
||||
</TwoColumns>
|
||||
|
||||
<section className="mb-8 p-4 rounded-lg shadow-lg bg-white flex flex-row justify-items-stretch ">
|
||||
@@ -72,9 +72,13 @@ const AssistantReply = () => {
|
||||
<Flex justify="center" ml="auto" gap={2}>
|
||||
<SkipButton>Skip</SkipButton>
|
||||
{endTask.task.type !== "task_done" ? (
|
||||
<SubmitButton onClick={() => submitResponse(tasks[0])}>Submit</SubmitButton>
|
||||
<SubmitButton data-cy="submit" onClick={() => submitResponse(tasks[0])}>
|
||||
Submit
|
||||
</SubmitButton>
|
||||
) : (
|
||||
<SubmitButton onClick={fetchNextTask}>Next Task</SubmitButton>
|
||||
<SubmitButton data-cy="next-task" onClick={fetchNextTask}>
|
||||
Next Task
|
||||
</SubmitButton>
|
||||
)}
|
||||
</Flex>
|
||||
</section>
|
||||
|
||||
@@ -64,7 +64,7 @@ const UserReply = () => {
|
||||
<Messages messages={task.conversation.messages} post_id={task.id} />
|
||||
{task.hint && <p className="text-lg py-1">Hint: {task.hint}</p>}
|
||||
</>
|
||||
<Textarea name="reply" placeholder="Reply..." ref={inputRef} />
|
||||
<Textarea name="reply" data-cy="reply" placeholder="Reply..." ref={inputRef} />
|
||||
</TwoColumns>
|
||||
|
||||
<section className="mb-8 p-4 rounded-lg shadow-lg bg-white flex flex-row justify-items-stretch ">
|
||||
@@ -72,9 +72,13 @@ const UserReply = () => {
|
||||
<Flex justify="center" ml="auto" gap={2}>
|
||||
<SkipButton>Skip</SkipButton>
|
||||
{endTask.task.type !== "task_done" ? (
|
||||
<SubmitButton onClick={() => submitResponse(tasks[0])}>Submit</SubmitButton>
|
||||
<SubmitButton data-cy="submit" onClick={() => submitResponse(tasks[0])}>
|
||||
Submit
|
||||
</SubmitButton>
|
||||
) : (
|
||||
<SubmitButton onClick={fetchNextTask}>Next Task</SubmitButton>
|
||||
<SubmitButton data-cy="next-task" onClick={fetchNextTask}>
|
||||
Next Task
|
||||
</SubmitButton>
|
||||
)}
|
||||
</Flex>
|
||||
</section>
|
||||
|
||||
@@ -78,11 +78,13 @@ const RankAssistantReplies = () => {
|
||||
<Flex justify="center" ml="auto" gap={2}>
|
||||
<SkipButton>Skip</SkipButton>
|
||||
{endTask.task.type !== "task_done" ? (
|
||||
<SubmitButton onClick={() => submitResponse(tasks[0])} disabled={ranking.length === 0}>
|
||||
<SubmitButton data-cy="submit" onClick={() => submitResponse(tasks[0])} disabled={ranking.length === 0}>
|
||||
Submit
|
||||
</SubmitButton>
|
||||
) : (
|
||||
<SubmitButton onClick={fetchNextTask}>Next Task</SubmitButton>
|
||||
<SubmitButton data-cy="next-task" onClick={fetchNextTask}>
|
||||
Next Task
|
||||
</SubmitButton>
|
||||
)}
|
||||
</Flex>
|
||||
</section>
|
||||
|
||||
@@ -77,11 +77,13 @@ const RankInitialPrompts = () => {
|
||||
<Flex justify="center" ml="auto" gap={2}>
|
||||
<SkipButton>Skip</SkipButton>
|
||||
{endTask.task.type !== "task_done" ? (
|
||||
<SubmitButton onClick={() => submitResponse(tasks[0])} disabled={ranking.length === 0}>
|
||||
<SubmitButton data-cy="submit" onClick={() => submitResponse(tasks[0])} disabled={ranking.length === 0}>
|
||||
Submit
|
||||
</SubmitButton>
|
||||
) : (
|
||||
<SubmitButton onClick={fetchNextTask}>Next Task</SubmitButton>
|
||||
<SubmitButton data-cy="next-task" onClick={fetchNextTask}>
|
||||
Next Task
|
||||
</SubmitButton>
|
||||
)}
|
||||
</Flex>
|
||||
</section>
|
||||
|
||||
@@ -78,11 +78,13 @@ const RankUserReplies = () => {
|
||||
<Flex justify="center" ml="auto" gap={2}>
|
||||
<SkipButton>Skip</SkipButton>
|
||||
{endTask.task.type !== "task_done" ? (
|
||||
<SubmitButton onClick={() => submitResponse(tasks[0])} disabled={ranking.length === 0}>
|
||||
<SubmitButton data-cy="submit" onClick={() => submitResponse(tasks[0])} disabled={ranking.length === 0}>
|
||||
Submit
|
||||
</SubmitButton>
|
||||
) : (
|
||||
<SubmitButton onClick={fetchNextTask}>Next Task</SubmitButton>
|
||||
<SubmitButton data-cy="next-task" onClick={fetchNextTask}>
|
||||
Next Task
|
||||
</SubmitButton>
|
||||
)}
|
||||
</Flex>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user