chore: plugin form builder e2e (#5612)
* chore: update plugin files to esm * chore: add e2e for plugin form builder * chore: update release script and gh workflow * chore: update build command for form builder plugin
This commit is contained in:
1
.github/workflows/main.yml
vendored
1
.github/workflows/main.yml
vendored
@@ -254,6 +254,7 @@ jobs:
|
||||
- fields/lexical
|
||||
- live-preview
|
||||
- localization
|
||||
- plugin-form-builder
|
||||
- plugin-nested-docs
|
||||
- plugin-seo
|
||||
# - refresh-permissions
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"scripts": {
|
||||
"build:swc": "swc ./src -d ./dist --config-file .swcrc",
|
||||
"build:types": "tsc --emitDeclarationOnly --outDir dist",
|
||||
"build": "echo \"Build temporarily disabled.\" && exit 0",
|
||||
"build": "swc ./src -d ./dist --config-file .swcrc",
|
||||
"clean": "rimraf {dist,*.tsbuildinfo}",
|
||||
"prepublishOnly": "pnpm clean && pnpm turbo build",
|
||||
"test": "echo \"No tests available.\""
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import type { PluginConfig } from '../../../types.js'
|
||||
|
||||
const createCharge = async (beforeChangeData: any, formConfig: PluginConfig): Promise<any> => {
|
||||
export const createCharge = async (
|
||||
beforeChangeData: any,
|
||||
formConfig: PluginConfig,
|
||||
): Promise<any> => {
|
||||
const { data, operation } = beforeChangeData
|
||||
|
||||
let dataWithPaymentDetails = data
|
||||
@@ -9,11 +12,10 @@ const createCharge = async (beforeChangeData: any, formConfig: PluginConfig): Pr
|
||||
const { handlePayment } = formConfig || {}
|
||||
|
||||
if (typeof handlePayment === 'function') {
|
||||
// eslint-disable-next-line @typescript-eslint/await-thenable
|
||||
dataWithPaymentDetails = await handlePayment(beforeChangeData)
|
||||
}
|
||||
}
|
||||
|
||||
return dataWithPaymentDetails
|
||||
}
|
||||
|
||||
export default createCharge
|
||||
|
||||
@@ -4,7 +4,7 @@ import { serializeLexical } from '../../../utilities/lexical/serializeLexical.js
|
||||
import { replaceDoubleCurlys } from '../../../utilities/replaceDoubleCurlys.js'
|
||||
import { serializeSlate } from '../../../utilities/slate/serializeSlate.js'
|
||||
|
||||
const sendEmail = async (beforeChangeData: any, formConfig: PluginConfig): Promise<any> => {
|
||||
export const sendEmail = async (beforeChangeData: any, formConfig: PluginConfig): Promise<any> => {
|
||||
const { data, operation, req } = beforeChangeData
|
||||
|
||||
if (operation === 'create') {
|
||||
@@ -98,5 +98,3 @@ const sendEmail = async (beforeChangeData: any, formConfig: PluginConfig): Promi
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
export default sendEmail
|
||||
|
||||
@@ -2,8 +2,8 @@ import type { CollectionConfig } from 'payload/types'
|
||||
|
||||
import type { PluginConfig } from '../../types.js'
|
||||
|
||||
import createCharge from './hooks/createCharge.js'
|
||||
import sendEmail from './hooks/sendEmail.js'
|
||||
import { createCharge } from './hooks/createCharge.js'
|
||||
import { sendEmail } from './hooks/sendEmail.js'
|
||||
|
||||
// all settings can be overridden by the config
|
||||
export const generateSubmissionCollection = (formConfig: PluginConfig): CollectionConfig => {
|
||||
@@ -36,10 +36,10 @@ export const generateSubmissionCollection = (formConfig: PluginConfig): Collecti
|
||||
if (!payload) return true
|
||||
|
||||
if (payload) {
|
||||
let existingForm
|
||||
let _existingForm
|
||||
|
||||
try {
|
||||
existingForm = await payload.findByID({
|
||||
_existingForm = await payload.findByID({
|
||||
id: value,
|
||||
collection: formSlug,
|
||||
req,
|
||||
|
||||
@@ -587,5 +587,3 @@ export const fields = {
|
||||
} as {
|
||||
[key: string]: ((fieldConfig?: FieldConfig | boolean) => Block) | Block
|
||||
}
|
||||
|
||||
export default fields
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { Config } from 'payload/config'
|
||||
|
||||
import type { PluginConfig } from './types'
|
||||
import type { PluginConfig } from './types.js'
|
||||
|
||||
import { generateSubmissionCollection } from './collections/FormSubmissions'
|
||||
import { generateFormCollection } from './collections/Forms'
|
||||
import { generateSubmissionCollection } from './collections/FormSubmissions/index.js'
|
||||
import { generateFormCollection } from './collections/Forms/index.js'
|
||||
|
||||
export { fields } from './collections/Forms/fields'
|
||||
export { getPaymentTotal } from './utilities/getPaymentTotal'
|
||||
export { fields } from './collections/Forms/fields.js'
|
||||
export { getPaymentTotal } from './utilities/getPaymentTotal.js'
|
||||
|
||||
const FormBuilder =
|
||||
(incomingFormConfig: PluginConfig) =>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { FieldValues, PaymentField, PriceCondition } from '../types'
|
||||
import type { FieldValues, PaymentField, PriceCondition } from '../types.js'
|
||||
|
||||
export const getPaymentTotal = (
|
||||
args: Partial<PaymentField> & {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { HTMLConverter } from '../types'
|
||||
import type { HTMLConverter } from '../types.js'
|
||||
|
||||
import { convertLexicalNodesToHTML } from '../serializeLexical'
|
||||
import { convertLexicalNodesToHTML } from '../serializeLexical.js'
|
||||
|
||||
export const HeadingHTMLConverter: HTMLConverter<any> = {
|
||||
async converter({ converters, node, parent, submissionData }) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { HTMLConverter } from '../types'
|
||||
import type { HTMLConverter } from '../types.js'
|
||||
|
||||
export const LinebreakHTMLConverter: HTMLConverter<any> = {
|
||||
converter() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { HTMLConverter } from '../types'
|
||||
import type { HTMLConverter } from '../types.js'
|
||||
|
||||
import { replaceDoubleCurlys } from '../../replaceDoubleCurlys'
|
||||
import { convertLexicalNodesToHTML } from '../serializeLexical'
|
||||
import { replaceDoubleCurlys } from '../../replaceDoubleCurlys.js'
|
||||
import { convertLexicalNodesToHTML } from '../serializeLexical.js'
|
||||
|
||||
export const LinkHTMLConverter: HTMLConverter<any> = {
|
||||
async converter({ converters, node, parent, submissionData }) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { HTMLConverter } from '../types'
|
||||
import type { HTMLConverter } from '../types.js'
|
||||
|
||||
import { convertLexicalNodesToHTML } from '../serializeLexical'
|
||||
import { convertLexicalNodesToHTML } from '../serializeLexical.js'
|
||||
|
||||
export const ListHTMLConverter: HTMLConverter<any> = {
|
||||
converter: async ({ converters, node, parent, submissionData }) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { HTMLConverter } from '../types'
|
||||
import type { HTMLConverter } from '../types.js'
|
||||
|
||||
import { convertLexicalNodesToHTML } from '../serializeLexical'
|
||||
import { convertLexicalNodesToHTML } from '../serializeLexical.js'
|
||||
|
||||
export const ParagraphHTMLConverter: HTMLConverter<any> = {
|
||||
async converter({ converters, node, parent, submissionData }) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { HTMLConverter } from '../types'
|
||||
import type { HTMLConverter } from '../types.js'
|
||||
|
||||
import { convertLexicalNodesToHTML } from '../serializeLexical'
|
||||
import { convertLexicalNodesToHTML } from '../serializeLexical.js'
|
||||
|
||||
export const QuoteHTMLConverter: HTMLConverter<any> = {
|
||||
async converter({ converters, node, parent, submissionData }) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { HTMLConverter } from '../types'
|
||||
import type { HTMLConverter } from '../types.js'
|
||||
|
||||
import { replaceDoubleCurlys } from '../../replaceDoubleCurlys'
|
||||
import { NodeFormat } from '../nodeFormat'
|
||||
import { replaceDoubleCurlys } from '../../replaceDoubleCurlys.js'
|
||||
import { NodeFormat } from '../nodeFormat.js'
|
||||
|
||||
export const TextHTMLConverter: HTMLConverter<any> = {
|
||||
converter({ node, submissionData }) {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { HTMLConverter } from './types'
|
||||
import type { HTMLConverter } from './types.js'
|
||||
|
||||
import { HeadingHTMLConverter } from './converters/heading'
|
||||
import { LinebreakHTMLConverter } from './converters/linebreak'
|
||||
import { LinkHTMLConverter } from './converters/link'
|
||||
import { ListHTMLConverter, ListItemHTMLConverter } from './converters/list'
|
||||
import { ParagraphHTMLConverter } from './converters/paragraph'
|
||||
import { QuoteHTMLConverter } from './converters/quote'
|
||||
import { TextHTMLConverter } from './converters/text'
|
||||
import { HeadingHTMLConverter } from './converters/heading.js'
|
||||
import { LinebreakHTMLConverter } from './converters/linebreak.js'
|
||||
import { LinkHTMLConverter } from './converters/link.js'
|
||||
import { ListHTMLConverter, ListItemHTMLConverter } from './converters/list.js'
|
||||
import { ParagraphHTMLConverter } from './converters/paragraph.js'
|
||||
import { QuoteHTMLConverter } from './converters/quote.js'
|
||||
import { TextHTMLConverter } from './converters/text.js'
|
||||
|
||||
export const defaultHTMLConverters: HTMLConverter[] = [
|
||||
ParagraphHTMLConverter,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { HTMLConverter, SerializedLexicalNodeWithParent } from './types'
|
||||
import type { HTMLConverter, SerializedLexicalNodeWithParent } from './types.js'
|
||||
|
||||
import { defaultHTMLConverters } from './defaultConverters'
|
||||
import { defaultHTMLConverters } from './defaultConverters.js'
|
||||
|
||||
export async function serializeLexical(data?: any, submissionData?: any): Promise<string> {
|
||||
const converters: HTMLConverter[] = defaultHTMLConverters
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import escapeHTML from 'escape-html'
|
||||
|
||||
import { replaceDoubleCurlys } from '../replaceDoubleCurlys'
|
||||
import { replaceDoubleCurlys } from '../replaceDoubleCurlys.js'
|
||||
|
||||
interface Node {
|
||||
bold?: boolean
|
||||
|
||||
@@ -27,7 +27,7 @@ const packageWhitelist = [
|
||||
'richtext-lexical',
|
||||
'plugin-cloud',
|
||||
'plugin-cloud-storage',
|
||||
// 'plugin-form-builder',
|
||||
'plugin-form-builder',
|
||||
'plugin-nested-docs',
|
||||
'plugin-redirects',
|
||||
'plugin-search',
|
||||
|
||||
144
test/plugin-form-builder/e2e.spec.ts
Normal file
144
test/plugin-form-builder/e2e.spec.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import type { Page } from '@playwright/test'
|
||||
|
||||
import { expect, test } from '@playwright/test'
|
||||
import * as path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
import type { PayloadTestSDK } from '../helpers/sdk/index.js'
|
||||
import type { Config } from './payload-types.js'
|
||||
|
||||
import { initPageConsoleErrorCatch } from '../helpers.js'
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
|
||||
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
|
||||
import { POLL_TOPASS_TIMEOUT } from '../playwright.config.js'
|
||||
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
|
||||
test.describe('Form Builder', () => {
|
||||
let page: Page
|
||||
let formsUrl: AdminUrlUtil
|
||||
let submissionsUrl: AdminUrlUtil
|
||||
let payload: PayloadTestSDK<Config>
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
const { payload: payloadFromInit, serverURL } = await initPayloadE2ENoConfig<Config>({
|
||||
dirname,
|
||||
})
|
||||
formsUrl = new AdminUrlUtil(serverURL, 'forms')
|
||||
submissionsUrl = new AdminUrlUtil(serverURL, 'form-submissions')
|
||||
|
||||
payload = payloadFromInit
|
||||
|
||||
const context = await browser.newContext()
|
||||
page = await context.newPage()
|
||||
initPageConsoleErrorCatch(page)
|
||||
})
|
||||
|
||||
test.describe('Forms collection', () => {
|
||||
test('has contact form', async () => {
|
||||
await page.goto(formsUrl.list)
|
||||
|
||||
await expect(() => expect(page.url()).toContain('forms')).toPass({
|
||||
timeout: POLL_TOPASS_TIMEOUT,
|
||||
})
|
||||
|
||||
const titleCell = page.locator('.row-1 .cell-title a')
|
||||
await expect(titleCell).toHaveText('Contact Form')
|
||||
const href = await titleCell.getAttribute('href')
|
||||
|
||||
await titleCell.click()
|
||||
await expect(() => expect(page.url()).toContain(href)).toPass({
|
||||
timeout: POLL_TOPASS_TIMEOUT,
|
||||
})
|
||||
|
||||
const nameField = page.locator('#field-fields__0__name')
|
||||
await expect(nameField).toHaveValue('name')
|
||||
|
||||
const addFieldsButton = page.locator('.blocks-field__drawer-toggler')
|
||||
|
||||
await addFieldsButton.click()
|
||||
|
||||
await expect(() => expect(page.locator('.drawer__header__title')).toBeVisible()).toPass({
|
||||
timeout: POLL_TOPASS_TIMEOUT,
|
||||
})
|
||||
|
||||
await page
|
||||
.locator('button.thumbnail-card', {
|
||||
hasText: 'Text Area',
|
||||
})
|
||||
.click()
|
||||
|
||||
await expect(() =>
|
||||
expect(
|
||||
page.locator('.pill__label', {
|
||||
hasText: 'Text Area',
|
||||
}),
|
||||
).toBeVisible(),
|
||||
).toPass({
|
||||
timeout: POLL_TOPASS_TIMEOUT,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Form submissions collection', () => {
|
||||
test('has form submissions', async () => {
|
||||
await page.goto(submissionsUrl.list)
|
||||
|
||||
await expect(() => expect(page.url()).toContain('form-submissions')).toPass({
|
||||
timeout: POLL_TOPASS_TIMEOUT,
|
||||
})
|
||||
|
||||
const idCell = page.locator('.row-1 .cell-id a')
|
||||
const href = await idCell.getAttribute('href')
|
||||
|
||||
await idCell.click()
|
||||
await expect(() => expect(page.url()).toContain(href)).toPass({
|
||||
timeout: POLL_TOPASS_TIMEOUT,
|
||||
})
|
||||
|
||||
await expect(page.locator('#field-submissionData__0__value')).toHaveValue('Test Submission')
|
||||
await expect(page.locator('#field-submissionData__1__value')).toHaveValue(
|
||||
'tester@example.com',
|
||||
)
|
||||
})
|
||||
|
||||
test('can create form submission', async () => {
|
||||
await page.goto(submissionsUrl.list)
|
||||
|
||||
const contactForm = await payload
|
||||
.find({
|
||||
collection: 'forms',
|
||||
})
|
||||
.then((data) => {
|
||||
return data[0]
|
||||
})
|
||||
|
||||
const createdSubmission = await payload.create({
|
||||
collection: 'form-submissions',
|
||||
data: {
|
||||
form: contactForm.id,
|
||||
submissionData: [
|
||||
{
|
||||
field: 'name',
|
||||
value: 'New tester',
|
||||
},
|
||||
{
|
||||
field: 'email',
|
||||
value: 'new@example.com',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
await page.goto(submissionsUrl.edit(createdSubmission.id))
|
||||
|
||||
await expect(() => expect(page.url()).toContain(createdSubmission.id)).toPass({
|
||||
timeout: POLL_TOPASS_TIMEOUT,
|
||||
})
|
||||
|
||||
await expect(page.locator('#field-submissionData__0__value')).toHaveValue('New tester')
|
||||
await expect(page.locator('#field-submissionData__1__value')).toHaveValue('new@example.com')
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user