mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-13 06:36:49 -05:00
Add test to adding new suggestion
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,6 +1,6 @@
|
||||
node_modules
|
||||
|
||||
/.cache
|
||||
/.cache*
|
||||
/build
|
||||
/public/build
|
||||
.env
|
||||
|
||||
@@ -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
110
app/db/seed.ts
Normal 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,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
]);
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
12
app/routes/seed.tsx
Normal 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;
|
||||
};
|
||||
@@ -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");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user