chore(plugin-stripe): scaffolds tests (#4510)

This commit is contained in:
Jacob Fletcher
2023-12-14 11:56:33 -05:00
committed by GitHub
parent 07371b9cad
commit 6d9110ec48
22 changed files with 131 additions and 145 deletions

View File

@@ -1,6 +0,0 @@
PAYLOAD_PUBLIC_CMS_URL=http://localhost:3000
DATABASE_URI=mongodb://localhost/payload-plugin-stripe
PAYLOAD_SECRET=
STRIPE_SECRET_KEY=
STRIPE_WEBHOOKS_ENDPOINT_SECRET=
PAYLOAD_PUBLIC_IS_STRIPE_TEST_KEY=true

View File

@@ -1,4 +0,0 @@
{
"exec": "ts-node src/server.ts",
"ext": "ts"
}

View File

@@ -1,33 +0,0 @@
{
"name": "payload-starter-typescript",
"description": "Blank template - no collections",
"version": "1.0.0",
"main": "dist/server.js",
"license": "MIT",
"scripts": {
"dev": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts nodemon",
"build:payload": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload build",
"build:server": "tsc",
"build": "yarn build:payload && yarn build:server",
"serve": "cross-env PAYLOAD_CONFIG_PATH=dist/demo/src/payload.config.js NODE_ENV=production node dist/demo/src/server.js",
"generate:types": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:types",
"clean": "rm -rf node_modules/@payloadcms/bundler-vite/node_modules/.vite build dist"
},
"dependencies": {
"@payloadcms/bundler-vite": "^0.1.4",
"@payloadcms/bundler-webpack": "^1.0.5",
"@payloadcms/db-mongodb": "^1.0.6",
"@payloadcms/richtext-lexical": "^0.1.16",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"payload": "^2.2.1",
"stripe": "^10.10.0"
},
"devDependencies": {
"@types/express": "^4.17.9",
"cross-env": "^7.0.3",
"nodemon": "^2.0.6",
"ts-node": "^9.1.1",
"typescript": "^4.1.3"
}
}

Binary file not shown.

View File

@@ -1,26 +0,0 @@
import dotenv from 'dotenv'
import express from 'express'
import payload from 'payload'
dotenv.config()
const app = express()
// Redirect root to Admin panel
app.get('/', (_, res) => {
res.redirect('/admin')
})
// Initialize Payload
const start = async (): Promise<void> => {
await payload.init({
secret: process.env.PAYLOAD_SECRET,
express: app,
onInit: () => {
payload.logger.info(`Payload Admin URL: ${payload.getAdminURL()}`)
},
})
app.listen(3000)
}
start()

View File

@@ -1,15 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"strict": false,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "./dist",
"rootDir": "../",
"jsx": "react"
},
"ts-node": {
"transpileOnly": true
}
}

View File

@@ -1,7 +1,8 @@
import type { UIField } from 'payload/dist/fields/config/types' import type { UIField } from 'payload/dist/fields/config/types'
import { useFormFields } from 'payload/components/forms' import { useFormFields } from 'payload/components/forms'
import CopyToClipboard from 'payload/dist/admin/components/elements/CopyToClipboard' // TODO: fix this import to work in dev mode within the monorepo in a way that is backwards compatible with 1.x
// import CopyToClipboard from 'payload/dist/admin/components/elements/CopyToClipboard'
import React from 'react' import React from 'react'
export const LinkToDoc: React.FC< export const LinkToDoc: React.FC<
@@ -32,7 +33,7 @@ export const LinkToDoc: React.FC<
View in Stripe View in Stripe
</span> </span>
{/* @ts-ignore */} {/* @ts-ignore */}
<CopyToClipboard value={href} /> {/* <CopyToClipboard value={href} /> */}
</div> </div>
<div <div
style={{ style={{

View File

@@ -20,5 +20,5 @@
"src/**/*.spec.tsx" "src/**/*.spec.tsx"
], ],
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.d.ts", "src/**/*.json"], "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.d.ts", "src/**/*.json"],
"references": [{ "path": "../payload" }] // db-mongodb depends on payload "references": [{ "path": "../payload" }]
} }

5
pnpm-lock.yaml generated
View File

@@ -8834,6 +8834,7 @@ packages:
which-boxed-primitive: 1.0.2 which-boxed-primitive: 1.0.2
which-collection: 1.0.1 which-collection: 1.0.1
which-typed-array: 1.1.11 which-typed-array: 1.1.11
dev: false
/deep-equal@2.2.3: /deep-equal@2.2.3:
resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==} resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==}
@@ -14252,7 +14253,7 @@ packages:
css-minimizer-webpack-plugin: 5.0.1(webpack@5.88.2) css-minimizer-webpack-plugin: 5.0.1(webpack@5.88.2)
dataloader: 2.2.2 dataloader: 2.2.2
date-fns: 2.30.0 date-fns: 2.30.0
deep-equal: 2.2.2 deep-equal: 2.2.3
deepmerge: 4.3.1 deepmerge: 4.3.1
dotenv: 8.6.0 dotenv: 8.6.0
express: 4.18.2 express: 4.18.2
@@ -14341,7 +14342,7 @@ packages:
uuid: 8.3.2 uuid: 8.3.2
webpack: 5.88.2(@swc/core@1.3.78)(webpack-cli@4.10.0) webpack: 5.88.2(@swc/core@1.3.78)(webpack-cli@4.10.0)
webpack-bundle-analyzer: 4.9.1 webpack-bundle-analyzer: 4.9.1
webpack-cli: 4.10.0(webpack@5.88.2) webpack-cli: 4.10.0(webpack-bundle-analyzer@4.9.1)(webpack@5.88.2)
webpack-dev-middleware: 6.0.1(webpack@5.88.2) webpack-dev-middleware: 6.0.1(webpack@5.88.2)
webpack-hot-middleware: 2.25.4 webpack-hot-middleware: 2.25.4
transitivePeerDependencies: transitivePeerDependencies:

View File

@@ -1,8 +1,10 @@
import { CollectionConfig } from 'payload/types' import type { CollectionConfig } from '../../../packages/payload/src/collections/config/types'
import { LinkToDoc } from '../../../src/ui/LinkToDoc'
const Customers: CollectionConfig = { import { LinkToDoc } from '../../../packages/plugin-stripe/src/ui/LinkToDoc'
slug: 'customers', import { customersSlug } from '../shared'
export const Customers: CollectionConfig = {
slug: customersSlug,
timestamps: true, timestamps: true,
admin: { admin: {
useAsTitle: 'email', useAsTitle: 'email',
@@ -32,7 +34,6 @@ const Customers: CollectionConfig = {
type: 'ui', type: 'ui',
admin: { admin: {
components: { components: {
// @ts-expect-error
Field: (args) => Field: (args) =>
LinkToDoc({ LinkToDoc({
...args, ...args,
@@ -109,5 +110,3 @@ const Customers: CollectionConfig = {
}, },
], ],
} }
export default Customers

View File

@@ -1,7 +1,9 @@
import { CollectionConfig } from 'payload/types' import type { CollectionConfig } from '../../../packages/payload/src/collections/config/types'
const Products: CollectionConfig = { import { productsSlug } from '../shared'
slug: 'products',
export const Products: CollectionConfig = {
slug: productsSlug,
timestamps: true, timestamps: true,
admin: { admin: {
defaultColumns: ['name'], defaultColumns: ['name'],
@@ -35,5 +37,3 @@ const Products: CollectionConfig = {
}, },
], ],
} }
export default Products

View File

@@ -1,6 +1,6 @@
import { CollectionConfig } from 'payload/types' import type { CollectionConfig } from '../../../packages/payload/src/collections/config/types'
const Users: CollectionConfig = { export const Users: CollectionConfig = {
slug: 'users', slug: 'users',
auth: true, auth: true,
admin: { admin: {
@@ -16,5 +16,3 @@ const Users: CollectionConfig = {
}, },
], ],
} }
export default Users

View File

@@ -1,36 +1,39 @@
import path from 'path' import stripePlugin from '../../packages/plugin-stripe/src'
import { buildConfig } from 'payload/config' import { buildConfigWithDefaults } from '../buildConfigWithDefaults'
import { viteBundler } from '@payloadcms/bundler-vite' import { devUser } from '../credentials'
// import { webpackBundler } from '@payloadcms/bundler-webpack' import { Customers } from './collections/Customers'
import { mongooseAdapter } from '@payloadcms/db-mongodb' import { Products } from './collections/Products'
import { lexicalEditor } from '@payloadcms/richtext-lexical' import { Users } from './collections/Users'
import { seed } from './seed'
import stripePlugin from '../../src'
import Customers from './collections/Customers'
import Products from './collections/Products'
import Users from './collections/Users'
import { subscriptionCreatedOrUpdated } from './webhooks/subscriptionCreatedOrUpdated' import { subscriptionCreatedOrUpdated } from './webhooks/subscriptionCreatedOrUpdated'
import { subscriptionDeleted } from './webhooks/subscriptionDeleted' import { subscriptionDeleted } from './webhooks/subscriptionDeleted'
import { syncPriceJSON } from './webhooks/syncPriceJSON' import { syncPriceJSON } from './webhooks/syncPriceJSON'
export default buildConfig({ process.env.STRIPE_WEBHOOKS_ENDPOINT_SECRET = 'whsec_123'
serverURL: process.env.PAYLOAD_PUBLIC_CMS_URL, process.env.STRIPE_SECRET_KEY = 'sk_test_123'
admin: {
user: Users.slug, export default buildConfigWithDefaults({
bundler: viteBundler(), collections: [Users, Products, Customers],
// bundler: webpackBundler(),
},
collections: [Users, Customers, Products],
editor: lexicalEditor({}),
localization: { localization: {
locales: ['en', 'es', 'de'],
defaultLocale: 'en', defaultLocale: 'en',
fallback: true, fallback: true,
locales: ['en', 'es', 'de'],
},
onInit: async (payload) => {
await payload.create({
collection: 'users',
data: {
email: devUser.email,
password: devUser.password,
},
})
await seed(payload)
}, },
plugins: [ plugins: [
stripePlugin({ stripePlugin({
stripeSecretKey: process.env.STRIPE_SECRET_KEY, stripeSecretKey: process.env.STRIPE_SECRET_KEY,
isTestKey: process.env.PAYLOAD_PUBLIC_IS_STRIPE_TEST_KEY === 'true', isTestKey: true,
logs: true, logs: true,
sync: [ sync: [
{ {
@@ -82,10 +85,4 @@ export default buildConfig({
stripeWebhooksEndpointSecret: process.env.STRIPE_WEBHOOKS_ENDPOINT_SECRET, stripeWebhooksEndpointSecret: process.env.STRIPE_WEBHOOKS_ENDPOINT_SECRET,
}), }),
], ],
typescript: {
outputFile: path.resolve(__dirname, 'payload-types.ts'),
},
db: mongooseAdapter({
url: process.env.DATABASE_URI,
}),
}) })

View File

@@ -0,0 +1,32 @@
import payload from '../../packages/payload/src'
import { initPayloadTest } from '../helpers/configHelpers'
describe('Stripe Plugin', () => {
beforeAll(async () => {
await initPayloadTest({ __dirname, init: { local: true } })
})
it('should create products', async () => {
const product = await payload.create({
collection: 'products',
data: {
name: 'Test Product',
},
})
expect(product).toHaveProperty('name', 'Test Product')
})
// Test various common API calls like `products.create`, etc.
// Send the requests through the Payload->Stripe proxy
// Query Stripe directly to ensure the data is as expected
it.todo('should open REST API proxy')
// Test various common webhook events like `product.created`, etc.
// These could potentially be mocked
it.todo('should handle incoming Stripe webhook events')
// Test that the data is synced to Stripe automatically without the use of custom hooks/proxy
// I.e. the `sync` config option
it.todo('should auto-sync data based on config')
})

View File

@@ -0,0 +1,23 @@
import type { Payload } from '../../../packages/payload/src'
import type { PayloadRequest } from '../../../packages/payload/types'
export const seed = async (payload: Payload): Promise<boolean> => {
payload.logger.info('Seeding data...')
const req = {} as PayloadRequest
try {
await payload.create({
collection: 'users',
data: {
email: 'demo@payloadcms.com',
password: 'demo',
},
req,
})
return true
} catch (err) {
console.error(err)
return false
}
}

View File

@@ -0,0 +1,5 @@
export const pagesSlug = 'pages'
export const productsSlug = 'products'
export const customersSlug = 'customers'

View File

@@ -1,7 +1,12 @@
import { APIError } from 'payload/errors' import { APIError } from '../../../packages/payload/errors'
export const subscriptionCreatedOrUpdated = async (args) => { export const subscriptionCreatedOrUpdated = async (args) => {
const { event, payload, stripe, stripeConfig } = args const {
event,
payload,
// stripe,
// stripeConfig
} = args
const customerStripeID = event.data.object.customer const customerStripeID = event.data.object.customer

View File

@@ -1,7 +1,12 @@
import { APIError } from 'payload/errors' import { APIError } from '../../../packages/payload/src/errors'
export const subscriptionDeleted = async (args) => { export const subscriptionDeleted = async (args) => {
const { event, payload, stripe, stripeConfig } = args const {
event,
payload,
// stripe,
// stripeConfig
} = args
const customerStripeID = event.data.object.customer const customerStripeID = event.data.object.customer
@@ -9,7 +14,10 @@ export const subscriptionDeleted = async (args) => {
`🪝 A new subscription was deleted in Stripe on customer ID: ${customerStripeID}, deleting from Payload...`, `🪝 A new subscription was deleted in Stripe on customer ID: ${customerStripeID}, deleting from Payload...`,
) )
const { id: eventID, plan } = event.data.object const {
id: eventID,
// plan
} = event.data.object
// Now look up the customer in Payload // Now look up the customer in Payload
try { try {

View File

@@ -31,17 +31,18 @@
}, },
"composite": true, // Required for references to work "composite": true, // Required for references to work
"references": [ "references": [
{ "path": "./packages/db-mongodb" },
// if your tsconfig is something different // if your tsconfig is something different
{ "path": "./packages/db-mongodb" },
{ "path": "./packages/db-postgres" }, { "path": "./packages/db-postgres" },
{ "path": "./packages/richtext-slate" }, { "path": "./packages/live-preview" },
{ "path": "./packages/richtext-lexical" }, { "path": "./packages/live-preview-react" },
{ "path": "./packages/payload" }, { "path": "./packages/payload" },
{ "path": "./packages/plugin-nested-docs" },
{ "path": "./packages/plugin-form-builder" },
{ "path": "./packages/plugin-cloud-storage" }, { "path": "./packages/plugin-cloud-storage" },
{ "path": "./packages/plugin-cloud" }, { "path": "./packages/plugin-cloud" },
{ "path": "./packages/live-preview" }, { "path": "./packages/plugin-form-builder" },
{ "path": "./packages/live-preview-react" } { "path": "./packages/plugin-nested-docs" },
{ "path": "./packages/plugin-stripe" },
{ "path": "./packages/richtext-slate" },
{ "path": "./packages/richtext-lexical" }
] ]
} }