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:
Paul
2024-04-02 20:56:37 -03:00
committed by GitHub
parent e1777dc533
commit 8174230afe
20 changed files with 189 additions and 46 deletions

View File

@@ -254,6 +254,7 @@ jobs:
- fields/lexical
- live-preview
- localization
- plugin-form-builder
- plugin-nested-docs
- plugin-seo
# - refresh-permissions

View File

@@ -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.\""

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -587,5 +587,3 @@ export const fields = {
} as {
[key: string]: ((fieldConfig?: FieldConfig | boolean) => Block) | Block
}
export default fields

View File

@@ -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) =>

View File

@@ -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> & {

View File

@@ -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 }) {

View File

@@ -1,4 +1,4 @@
import type { HTMLConverter } from '../types'
import type { HTMLConverter } from '../types.js'
export const LinebreakHTMLConverter: HTMLConverter<any> = {
converter() {

View File

@@ -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 }) {

View File

@@ -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 }) => {

View File

@@ -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 }) {

View File

@@ -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 }) {

View File

@@ -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 }) {

View File

@@ -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,

View File

@@ -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

View File

@@ -1,6 +1,6 @@
import escapeHTML from 'escape-html'
import { replaceDoubleCurlys } from '../replaceDoubleCurlys'
import { replaceDoubleCurlys } from '../replaceDoubleCurlys.js'
interface Node {
bold?: boolean

View File

@@ -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',

View 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')
})
})
})