Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .env.example

This file was deleted.

3 changes: 2 additions & 1 deletion app/modules/anilist/request.server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { setTimeout } from "node:timers/promises"
import { inspect } from "node:util"
import { env } from "../env.server"

type AnyRecord = { [key: string]: unknown }

Expand Down Expand Up @@ -29,7 +30,7 @@ export async function anilistRequest<
headers.Authorization = `Bearer ${accessToken}`
}

const response = await fetch("https://graphql.anilist.co", {
const response = await fetch(env.ANILIST_API_URL, {
method: "POST",
headers,
body: JSON.stringify({ query, variables }),
Expand Down
11 changes: 6 additions & 5 deletions app/modules/auth/session.server.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { createCookie } from "@remix-run/node"
import { raise } from "~/modules/common/errors"
import { env } from "../env.server"

const cookie = createCookie("session", {
secrets: [process.env.COOKIE_SECRET ?? raise("COOKIE_SECRET not set")],
secrets: [env.COOKIE_SECRET],
httpOnly: true,
maxAge: 60 * 60 * 24 * 365,
sameSite: "lax",
Expand All @@ -17,17 +18,17 @@ export async function createAnilistSession(authCallbackUrl: string) {
new URL(authCallbackUrl).searchParams.get("code") ??
raise("Anilist auth error: code not found in auth callback url")

const response = await fetch("https://anilist.co/api/v2/oauth/token", {
const response = await fetch(env.ANILIST_AUTH_TOKEN_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
},
body: JSON.stringify({
grant_type: "authorization_code",
client_id: process.env.ANILIST_CLIENT_ID,
client_secret: process.env.ANILIST_CLIENT_SECRET,
redirect_uri: process.env.ANILIST_REDIRECT_URI,
client_id: env.ANILIST_CLIENT_ID,
client_secret: env.ANILIST_CLIENT_SECRET,
redirect_uri: env.ANILIST_REDIRECT_URI,
code,
}),
})
Expand Down
4 changes: 2 additions & 2 deletions app/modules/dates/timezone-cookie.server.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { createCookie } from "@remix-run/node"
import { raise } from "~/modules/common/errors"
import { env } from "../env.server"

const cookie = createCookie("timezone", {
secrets: [process.env.COOKIE_SECRET ?? raise("COOKIE_SECRET not set")],
secrets: [env.COOKIE_SECRET],
httpOnly: true,
maxAge: 60 * 60 * 24 * 365,
sameSite: "lax",
Expand Down
14 changes: 14 additions & 0 deletions app/modules/env.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { raise } from "./common/errors"

const getEnv = (name: string) =>
process.env[name] ?? raise(`Missing environment variable: ${name}`)

export const env = {
ANILIST_API_URL: getEnv("ANILIST_API_URL"),
ANILIST_AUTH_TOKEN_URL: getEnv("ANILIST_AUTH_TOKEN_URL"),
ANILIST_CLIENT_ID: getEnv("ANILIST_CLIENT_ID"),
ANILIST_CLIENT_SECRET: getEnv("ANILIST_CLIENT_SECRET"),
ANILIST_REDIRECT_URI: getEnv("ANILIST_REDIRECT_URI"),
COOKIE_SECRET: getEnv("COOKIE_SECRET"),
REDIS_URL: getEnv("REDIS_URL"),
}
3 changes: 2 additions & 1 deletion app/modules/redis.server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { RedisClientType } from "redis"
import { commandOptions, createClient } from "redis"
import { env } from "./env.server"

export async function redisGetBuffer(key: string) {
const client = await getRedisClient()
Expand Down Expand Up @@ -29,7 +30,7 @@ function getRedisClient() {
}

async function createConnectedClient() {
const client = createClient<{}, {}, {}>({ url: process.env.REDIS_URL })
const client = createClient<{}, {}, {}>({ url: env.REDIS_URL })
await client.connect()
return client
}
Expand Down
9 changes: 3 additions & 6 deletions app/routes/auth/anilist.login.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import type { ActionFunction } from "@remix-run/node"
import { redirect } from "@remix-run/node"
import { raise } from "~/modules/common/errors"
import { env } from "~/modules/env.server"

export const loader: ActionFunction = () => {
const params = new URLSearchParams({
client_id:
process.env.ANILIST_CLIENT_ID ?? raise("ANILIST_CLIENT_ID not defined"),
redirect_uri:
process.env.ANILIST_REDIRECT_URI ??
raise("ANILIST_REDIRECT_URI not defined"),
client_id: env.ANILIST_CLIENT_ID,
redirect_uri: env.ANILIST_REDIRECT_URI,
response_type: "code",
})
return redirect(`https://anilist.co/api/v2/oauth/authorize?${params}`)
Expand Down
9 changes: 9 additions & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { defineConfig } from "cypress"

export default defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
})
22 changes: 22 additions & 0 deletions cypress/e2e/media-card.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export {}

it("shows media links", () => {
cy.visit("http://localhost:3000/schedule")

// waits until the browser is finished with its work before we start doing things
cy.window().then((win) => {
return new Promise((resolve) => {
win.requestIdleCallback(resolve, { timeout: 1000 })
})
})

cy.findAllByRole(/button|combobox/, { name: /external links/i })
.first()
.click()

cy.findByRole("menu", { name: /external links/i }).within(() => {
cy.findByRole(/link|menuitem/, { name: /anilist/i })
.then((link) => link.attr("href"))
.should("contain", "anilist.co")
})
})
3 changes: 3 additions & 0 deletions cypress/support/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/// <reference types="cypress" />
/// <reference types="@testing-library/cypress" />
import "@testing-library/cypress/add-commands"
13 changes: 13 additions & 0 deletions cypress/support/e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import "./commands"

const ignoredErrors = [
// react's streaming server render doesn't like cypress right now
"Hydration failed because the initial UI does not match what was rendered on the server.",
"There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.",
]

Cypress.on("uncaught:exception", (err) => {
if (ignoredErrors.some((error) => err.message.includes(error))) {
return false
}
})
8 changes: 6 additions & 2 deletions test/anilist-api-mock-server.mts → mocks/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { setupServer } from "msw/node"
import type {
ScheduleQuery,
ScheduleQueryVariables,
} from "~/generated/anilist-graphql"
} from "../app/generated/anilist-graphql"
import schedule from "./fixtures/schedule.json"

export const anilistApiMockServer = setupServer(
const anilistApiMockServer = setupServer(
graphql.query<ScheduleQuery, ScheduleQueryVariables>(
"Schedule",
(request, response, context) => {
Expand All @@ -21,3 +21,7 @@ export const anilistApiMockServer = setupServer(
},
),
)

if (process.env.NODE_ENV === "test") {
anilistApiMockServer.listen()
}
File renamed without changes.
15 changes: 9 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
"private": true,
"scripts": {
"dev": "cross-env NODE_ENV=development run-p --race --print-label dev:*",
"dev:remix": "remix dev",
"dev:remix": "binode -r esbuild-register -r ./mocks/api -- @remix-run/dev:remix dev",
"dev:graphql": "pnpm run graphql --watch",
"dev:tailwind": "pnpm run tailwind --watch",
"dev:docker": "docker-compose up",
"dev:routes": "remix-routes -w",
"dev-test": "cross-env NODE_ENV=test run-p --race --print-label dev:* dev-test:*",
"dev-test:cypress": "cypress open --e2e --browser electron",
"build": "remix-routes && pnpm run graphql && pnpm run tailwind --minify && remix build",
"start": "cross-env NODE_ENV=production remix-serve build",
"test": "echo todo lol",
Expand All @@ -36,7 +38,6 @@
"cross-env": "^7.0.3",
"date-fns": "^2.28.0",
"date-fns-tz": "^1.3.6",
"dotenv": "^16.0.1",
"framer-motion": "^6.5.1",
"graphql": "^16.5.0",
"lodash-es": "^4.17.21",
Expand All @@ -54,25 +55,27 @@
"@graphql-codegen/cli": "2.9.1",
"@graphql-codegen/typescript": "2.7.2",
"@graphql-codegen/typescript-operations": "2.5.2",
"@playwright/test": "^1.23.4",
"@remix-run/dev": "deferred",
"@remix-run/serve": "deferred",
"@rushstack/eslint-patch": "^1.1.4",
"@tailwindcss/line-clamp": "^0.4.0",
"@testing-library/cypress": "^8.0.3",
"@types/eslint": "^8.4.5",
"@types/lodash-es": "^4.17.6",
"@types/node": "^18.0.6",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"@types/sharp": "^0.30.4",
"binode": "^1.0.5",
"cypress": "^10.3.1",
"dotenv": "^16.0.1",
"esbuild-register": "^3.3.3",
"eslint": "^8.20.0",
"msw": "^0.44.2",
"npm-run-all": "^4.1.5",
"playwright": "^1.23.4",
"prettier": "^2.7.1",
"tailwindcss": "^3.1.6",
"typescript": "^4.7.4",
"vitest": "^0.18.1"
"typescript": "^4.7.4"
},
"sideEffects": false,
"prettier": "@itsmapleleaf/configs/prettier"
Expand Down
Loading