Add test to adding new suggestion

This commit is contained in:
Kalle
2022-06-04 13:10:00 +03:00
parent 7e25c073e5
commit c4af9bfd95
11 changed files with 165 additions and 12 deletions

2
.gitignore vendored
View File

@@ -1,6 +1,6 @@
node_modules
/.cache
/.cache*
/build
/public/build
.env

View File

@@ -60,6 +60,7 @@ export function Combobox<T extends Record<string, string | null | number>>({
displayValue={(option) =>
(option as Unpacked<typeof options>)?.label ?? ""
}
data-cy={`${inputName}-combobox-input`}
/>
<HeadlessCombobox.Options
className={clsx("combobox-options", {

110
app/db/seed.ts Normal file
View File

@@ -0,0 +1,110 @@
import { db } from "~/db";
import { sql } from "~/db/sql";
import { faker } from "@faker-js/faker";
import type { User } from "~/db/types";
import invariant from "tiny-invariant";
import { upcomingVoting } from "~/core/plus";
const ADMIN_TEST_DISCORD_ID = "79237403620945920";
const ADMIN_TEST_AVATAR = "fcfd65a3bea598905abb9ca25296816b";
const NZAP_TEST_DISCORD_ID = "455039198672453645";
const NZAP_TEST_AVATAR = "f809176af93132c3db5f0a5019e96339"; // https://cdn.discordapp.com/avatars/455039198672453645/f809176af93132c3db5f0a5019e96339.webp?size=160
const basicSeeds = [
adminUser,
nzapUser,
users,
plusTierToUsers,
plusSuggestions,
];
export function seed() {
wipeDB();
for (const seedFunc of basicSeeds) {
seedFunc();
}
}
function wipeDB() {
const tablesToDelete = ["User"];
for (const table of tablesToDelete) {
sql.prepare(`delete from "${table}"`).run();
}
}
function adminUser() {
db.users.upsert({
discordDiscriminator: "4059",
discordId: ADMIN_TEST_DISCORD_ID,
discordName: "Sendou",
twitch: "Sendou",
youtubeId: "UCWbJLXByvsfQvTcR4HLPs5Q",
discordAvatar: ADMIN_TEST_AVATAR,
twitter: "sendouc",
});
}
function nzapUser() {
db.users.upsert({
discordDiscriminator: "6227",
discordId: NZAP_TEST_DISCORD_ID,
discordName: "N-ZAP",
twitch: null,
youtubeId: null,
discordAvatar: NZAP_TEST_AVATAR,
twitter: null,
});
}
function users() {
new Array(500).fill(null).map(fakeUser).forEach(db.users.upsert);
}
function fakeUser() {
return {
discordAvatar: null,
discordDiscriminator: String(faker.random.numeric(4)),
discordId: String(faker.random.numeric(17)),
discordName: faker.random.word(),
twitch: null,
twitter: null,
youtubeId: null,
};
}
function plusTierToUsers() {
sql.prepare(`update "User" set "plusTier" = 3 where id < 150`).run();
sql.prepare(`update "User" set "plusTier" = 2 where id < 80`).run();
sql.prepare(`update "User" set "plusTier" = 1 where id < 30`).run();
// omit N-ZAP user for testing
sql.prepare(`update "User" set "plusTier" = null where id = 2`).run();
}
function plusSuggestions() {
const usersInPlus = sql
.prepare(`select * from "User" where "plusTier" is not null and "id" != 1`) // exclude admin
.all() as User[];
const { month, year } = upcomingVoting(new Date());
for (let userId = 150; userId < 190; userId++) {
const amountOfSuggestions = faker.helpers.arrayElement([1, 1, 2, 3, 4]);
for (let i = 0; i < amountOfSuggestions; i++) {
const suggester = usersInPlus.shift();
invariant(suggester);
invariant(suggester.plusTier);
db.plusSuggestions.create({
authorId: suggester.id,
month,
year,
suggestedId: userId,
text: faker.lorem.lines(),
tier: suggester.plusTier,
});
}
}
}

View File

@@ -45,9 +45,12 @@ interface CanDeleteCommentArgs {
suggestions: plusSuggestions.FindVisibleForUser;
}
export function canDeleteComment(args: CanDeleteCommentArgs) {
const votingActive =
process.env.NODE_ENV === "test" ? false : isVotingActive();
if (isFirstSuggestion(args)) {
return allTruthy([
!isVotingActive(),
!votingActive,
isOwnComment(args),
suggestionHasNoOtherComments(args),
]);
@@ -133,8 +136,11 @@ export function canSuggestNewUserFE({
user,
suggestions,
}: CanSuggestNewUserFEArgs) {
const votingActive =
process.env.NODE_ENV === "test" ? false : isVotingActive();
return allTruthy([
!isVotingActive(),
!votingActive,
!hasUserSuggestedThisMonth({ user, suggestions }),
isPlusServerMember(user),
]);

View File

@@ -4,7 +4,9 @@ import { IMPERSONATED_SESSION_KEY } from "~/core/auth/authenticator.server";
import { sessionStorage } from "~/core/auth/session.server";
export const action: ActionFunction = async ({ request }) => {
if (!["development", "test"].includes(process.env.NODE_ENV)) return null;
if (process.env.NODE_ENV === "production") {
throw new Response(null, { status: 400 });
}
const session = await sessionStorage.getSession(
request.headers.get("Cookie")

View File

@@ -162,7 +162,9 @@ export default function PlusSuggestionsPage() {
</div>
{canSuggestNewUserFE({ user, suggestions: data.suggestions }) ? (
// TODO: resetScroll={false} https://twitter.com/ryanflorence/status/1527775882797907969
<LinkButton to="new">Suggest</LinkButton>
<LinkButton to="new" data-cy="new-suggest-button">
Suggest
</LinkButton>
) : null}
</div>
<div className="stack lg">

View File

@@ -121,6 +121,7 @@ export default function PlusNewSuggestionModalPage() {
<select
id="tier"
name="tier"
data-cy="tier-select"
className="plus__modal-select"
value={targetPlusTier}
onChange={(e) => setTargetPlusTier(Number(e.target.value))}

12
app/routes/seed.tsx Normal file
View File

@@ -0,0 +1,12 @@
import type { ActionFunction } from "@remix-run/node";
import { seed } from "~/db/seed";
export const action: ActionFunction = () => {
if (process.env.NODE_ENV === "production") {
throw new Response(null, { status: 400 });
}
seed();
return null;
};

View File

@@ -31,5 +31,28 @@ describe("Plus suggestions page", () => {
cy.contains("Cracked!").should("not.exist");
});
// xxx: test adding completely new suggestion, validation works
it.only("adds a new suggestion, validates suggested user and deletes it", () => {
cy.clock(new Date(Date.UTC(2022, 5, 15))); // let's make sure voting is not happening
cy.auth();
cy.visit(PLUS_SUGGESTIONS_PAGE);
cy.getCy("new-suggest-button").click();
cy.getCy("tier-select").select("2");
cy.getCy("user-combobox-input").type("Sendou{enter}");
cy.contains("This user already has access");
cy.getCy("submit-button").should("be.disabled");
cy.getCy("user-combobox-input").clear().type("N-ZAP{enter}");
cy.getCy("comment-textarea").type("So good");
cy.getCy("submit-button").click();
cy.getCy("plus2-radio").click();
cy.contains("N-ZAP");
cy.getCy("comments-summary").first().click();
cy.getCy("delete-comment-button").first().click();
cy.getCy("confirm-button").click();
cy.contains("N-ZAP").should("not.exist");
});
});

View File

@@ -15,9 +15,8 @@ Cypress.Commands.add("getCy", (id) => {
return cy.get(`[data-cy=${id}]`);
});
// TODO: make this a request instead... probably faster?
Cypress.Commands.add("seed", () => {
cy.exec("npm run seed:cypress");
cy.request("POST", `/seed`);
});
Cypress.Commands.add("auth", (id = 1) => {

View File

@@ -3,8 +3,5 @@
*/
module.exports = {
ignoredRouteFiles: ["**/.*"],
// appDirectory: "app",
// assetsBuildDirectory: "public/build",
// serverBuildPath: "build/index.js",
// publicPath: "/build/",
cacheDirectory: process.env.NODE_ENV === "test" ? ".cache-test" : undefined,
};