Skip to content

Commit

Permalink
fix: add nextjs-pages example to CI
Browse files Browse the repository at this point in the history
also fixes how the body is used in nextjs-pages is used
  • Loading branch information
CahidArda committed Nov 11, 2024
1 parent fc9d22a commit 6a9498e
Show file tree
Hide file tree
Showing 11 changed files with 425 additions and 64 deletions.
43 changes: 42 additions & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ env:
QSTASH_TOKEN: ${{ secrets.QSTASH_TOKEN }}
UPSTASH_REDIS_REST_URL: ${{ secrets.UPSTASH_REDIS_REST_URL }}
UPSTASH_REDIS_REST_TOKEN: ${{ secrets.UPSTASH_REDIS_REST_TOKEN }}
QSTASH_CURRENT_SIGNING_KEY: ${{ secrets.QSTASH_CURRENT_SIGNING_KEY }}
QSTASH_NEXT_SIGNING_KEY: ${{ secrets.QSTASH_NEXT_SIGNING_KEY }}

jobs:
local-tests:
Expand Down Expand Up @@ -574,7 +576,7 @@ jobs:
working-directory: examples/ci

cloudflare-workers-hono-deployed:
concurrency: cloudflare-workers-deployed
concurrency: cloudflare-workers-hono-deployed
needs:
- release
runs-on: ubuntu-latest
Expand Down Expand Up @@ -605,6 +607,8 @@ jobs:
run: |
echo '[vars]' >> wrangler.toml
echo "QSTASH_TOKEN = \"$QSTASH_TOKEN\"" >> ./wrangler.toml
echo "QSTASH_CURRENT_SIGNING_KEY = \"$QSTASH_CURRENT_SIGNING_KEY\"" >> ./wrangler.toml
echo "QSTASH_NEXT_SIGNING_KEY = \"$QSTASH_NEXT_SIGNING_KEY\"" >> ./wrangler.toml
echo "UPSTASH_REDIS_REST_URL = \"$UPSTASH_REDIS_REST_URL\"" >> ./wrangler.toml
echo "UPSTASH_REDIS_REST_TOKEN = \"$UPSTASH_REDIS_REST_TOKEN\"" >> ./wrangler.toml
working-directory: examples/cloudflare-workers-hono
Expand Down Expand Up @@ -656,3 +660,40 @@ jobs:
- name: Test
run: node ci.mjs
working-directory: examples/nextjs-12

nextjs-pages-deployed:
concurrency: nextjs-pages-deployed
runs-on: ubuntu-latest
needs:
- release
steps:
- name: Setup repo
uses: actions/checkout@v3
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: 20

- name: Setup Bun
uses: oven-sh/setup-bun@v1
with:
bun-version: latest

- uses: pnpm/action-setup@v2
with:
version: latest

- name: Deploy
# TODO: use ci
run: |
pnpm add @upstash/workflow@latest
DEPLOYMENT_URL=$(npx vercel --token=${{ secrets.VERCEL_TOKEN }})
echo "DEPLOYMENT_URL=${DEPLOYMENT_URL}" >> $GITHUB_ENV
env:
VERCEL_ORG_ID: ${{secrets.VERCEL_TEAM_ID}}
VERCEL_PROJECT_ID: "prj_JRuNjBlCZA90HAN32okkfOovLLwf"
working-directory: examples/nextjs-pages

- name: Test
run: bun test ci.test.ts
working-directory: examples/nextjs-pages
10 changes: 6 additions & 4 deletions examples/bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ project_arg="$1"


# create dist
# cd ..
# bun install
# bun run build
# cd examples
cd ..
bun install
bun run build
cd examples/$project_arg
pnpm i @upstash/workflow@file:../../dist
cd ..

# install dependencies
cd "$project_arg"
Expand Down
148 changes: 108 additions & 40 deletions examples/cloudflare-workers-hono/ci.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,118 @@ import { Client } from "@upstash/qstash"
import { Redis } from "@upstash/redis"
import { serve } from "@upstash/workflow/nextjs"
import { describe, test, expect } from "bun:test"
import { RedisEntry } from "./src/app"

const qstashClient = new Client({
baseUrl: "https://workflow-tests.requestcatcher.com/",
token: "mock"
})

// @ts-expect-error mocking publishJSON
qstashClient.publishJSON = async () => {
return { messageId: "msgId" }
type TestConfig = {
testDescription: string,
route: string,
payload: undefined | string | object,
headers: Record<string, string>,
expectedResult: unknown
}

const { POST: serveHandler } = serve(
async (context) => {
await context.sleep("sleeping", 10)
}, {
qstashClient,
receiver: undefined
const tests: TestConfig[] = [
{
testDescription: "should return undefined from empty string",
route: "ci",
payload: "",
headers: {},
expectedResult: `step 1 input: 'undefined', type: 'undefined', stringified input: 'undefined'`
},
{
testDescription: "should return foo correctly",
route: "ci",
payload: "foo",
headers: {},
expectedResult: `step 1 input: 'foo', type: 'string', stringified input: '"foo"'`
},
{
testDescription: "should allow json without space",
route: "ci",
payload: `{"foo":"bar"}`,
headers: {},
expectedResult: `step 1 input: '[object Object]', type: 'object', stringified input: '{"foo":"bar"}'`
},
{
testDescription: "should allow json with one space",
route: "ci",
payload: `{"foo": "bar"}`,
headers: {},
expectedResult: `step 1 input: '[object Object]', type: 'object', stringified input: '{"foo":"bar"}'`
},
{
testDescription: "should allow json with 3 spaces",
route: "ci",
payload: `{ "foo" : "bar" }`,
headers: {},
expectedResult: `step 1 input: '[object Object]', type: 'object', stringified input: '{"foo":"bar"}'`
}
)
]

describe("cloudflare workers tests", () => {
const testEndpoint = ({
testDescription,
route,
payload,
headers,
expectedResult,
}: TestConfig) => {
test(testDescription, async () => {
if (!process.env.DEPLOYMENT_URL) {
throw new Error("can't run test without deployment url.")
}

const redis = Redis.fromEnv()
const client = new Client({
baseUrl: process.env.QSTASH_URL,
token: process.env.QSTASH_TOKEN!
})

const secret = "secret-" + Math.floor(Math.random() * 10000).toString()

await client.publish({
url: `${process.env.DEPLOYMENT_URL}/${route}`,
body: typeof payload === "object" ? JSON.stringify(payload) : payload,
method: "POST",
headers: {
"secret-header": secret,
...headers
}
})

await new Promise(r => setTimeout(r, 4000));

const result = await redis.get<RedisEntry>(`ci-cf-ran-${secret}`)

expect(result).toBeDefined()
expect(result?.secret).toBe(secret)
expect(result?.result).toBe(expectedResult)
}, {
timeout: 8000
})
}

describe("cloudflare workers", () => {
test("should send first invocation", async () => {

const qstashClient = new Client({
baseUrl: "https://workflow-tests.requestcatcher.com/",
token: "mock"
})

// @ts-expect-error mocking publishJSON
qstashClient.publishJSON = async () => {
return { messageId: "msgId" }
}

const { POST: serveHandler } = serve(
async (context) => {
await context.sleep("sleeping", 10)
}, {
qstashClient,
receiver: undefined
}
)

const request = new Request("https://workflow-tests.requestcatcher.com/")
const response = await serveHandler(request)

Expand All @@ -36,30 +126,8 @@ describe("cloudflare workers tests", () => {
})

if (process.env.DEPLOYMENT_URL) {
test("should run workflow successfully", async () => {
const redis = Redis.fromEnv()
const client = new Client({ token: process.env.QSTASH_TOKEN! })

const secret = "secret-" + Math.floor(Math.random() * 10000).toString()
await client.publishJSON({
url: `${process.env.DEPLOYMENT_URL}/ci`,
body: { text: "hello world!" },
method: "POST",
headers: {
"Content-type": "text/plain",
"secret-header": secret
}
})

await new Promise(r => setTimeout(r, 4000));

const result = await redis.get<string>(`ci-cf-ran-${secret}`)

if (result !== secret) {
throw new Error("Cloudflare workflow didn't run")
}
}, {
timeout: 8000
tests.forEach(test => {
testEndpoint(test)
})
} else {
console.log("skipping workflow run tests because DEPLOYMENT_URL is not set");
Expand Down
32 changes: 21 additions & 11 deletions examples/cloudflare-workers-hono/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,32 +40,42 @@ app.post(
*/
app.post(
"/ci",
serve<{ text: string }>(
serve(
async (context) => {
const input = context.requestPayload.text;
const input = context.requestPayload
const result1 = await context.run("step1", async () => {
const output = someWork(input);
console.log("step 1 input", input, "output", output);
return output;
const output = `step 1 input: '${input}', type: '${typeof input}', stringified input: '${JSON.stringify(input)}'`
return output
});

await context.sleep("sleep", 1);

const secret = context.headers.get("secret-header")
if (!secret) {
console.error("secret not found");
throw new Error("secret not found. can't end the CI workflow")
} else {
console.log("saving secret to redis");
// @ts-expect-error env isn't typed
const redis = Redis.fromEnv(context.env)
await redis.set(`ci-cf-ran-${secret}`, secret, { ex: 30 })
await redis.set<RedisEntry>(
`ci-cf-ran-${secret}`,
{
secret,
result: result1
},
{ ex: 30 }
)
}
},
{
receiver: undefined,
},
),
retries: 0,
}
)
);

export type RedisEntry = {
secret: string,
result: unknown
}

export default app;
Loading

0 comments on commit 6a9498e

Please sign in to comment.