Skip to content

Commit

Permalink
test: newsletter flow basics -d
Browse files Browse the repository at this point in the history
  • Loading branch information
arpowers committed Oct 23, 2024
1 parent 9e2847c commit ff2fcff
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 46 deletions.
2 changes: 2 additions & 0 deletions @fiction/core/test-utils/buildTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ export async function performActions(args: {
break
}
case 'hasValue': {
await element.first().waitFor({ state: 'visible', timeout: 20000 })
logger.info('HAS_VALUE', { data: { selector: action.selector, text: action.text } })
await playwrightTest.expect(element).toHaveValue(action.text || '')
break
Expand Down Expand Up @@ -421,6 +422,7 @@ export async function performActions(args: {
expect(await frameElement.isVisible(), `${frameAction.selector} is visible in frame`).toBe(true)
break
case 'hasValue':
await frameElement.waitFor({ state: 'visible', timeout: 20000 })
logger.info('HAS_VALUE', { data: { selector: frameAction.selector, text: frameAction.text } })
await playwrightTest.expect(frameElement).toHaveValue(frameAction.text || '')
break
Expand Down
3 changes: 2 additions & 1 deletion @fiction/plugins/plugin-newsletter/admin/EmailEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ async function saveBeforeNavigate(args: { location: string, href: string }) {
/>
<CardButton
:card
data-test-id="review-send-button"
theme="primary"
design="outline"
size="md"
Expand All @@ -116,7 +117,7 @@ async function saveBeforeNavigate(args: { location: string, href: string }) {
<ElPostEditor :post="campaign.post.value" :card @update:post="campaign.saveUtility.autosave()">
<template #footer>
<div v-if="actions.length" class="mt-12 pt-12">
<ElActions :actions ui-size="xl" class="flex gap-4" />
<ElActions :actions ui-size="xl" class="flex gap-4" data-test-id="editor-actions" />
</div>
</template>
</ElPostEditor>
Expand Down
51 changes: 24 additions & 27 deletions @fiction/plugins/plugin-newsletter/admin/ManageOverview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,16 @@ function _getPanelLink(panel: 'compose' | 'delivery' | 'analytics' | '') {
return card.link(`/manage-newsletter/${panel}?campaignId=${campaign?.campaignId}`)
}
async function saveBeforeNavigate(args: { location: string, href: string }) {
loading.value = args.location
if (campaign?.saveUtility.isDirty.value)
await campaign?.save({ disableNotify: true })
loading.value = ''
await card.goto(args.href)
}
const options = vue.computed(() => {
const config = campaign?.toConfig() as EmailCampaignConfig
const post = config.post
Expand Down Expand Up @@ -105,15 +115,18 @@ const options = vue.computed(() => {
subLabel: 'The text of the email',
input: 'InputControl',
valueDisplay: () => {
const isReady = wordCount > 10
return {
status: wordCount > 5 ? 'ready' : 'incomplete',
data: `${wordCount} Words in Email`,
status: isReady ? 'ready' : 'incomplete',
data: isReady ? `${wordCount} Words in Email` : 'Add Content',
message: isReady ? '' : 'Add at least 10 words to the email content.',
}
},
actions: () => [
{
testId: 'email-composer-link',
name: 'Email Composer',
href: getCampaignLink('newsletter-composer'),
onClick: () => saveBeforeNavigate({ location: 'newsletter-composer-link', href: getCampaignLink('newsletter-composer') }),
theme: 'theme',
icon: { class: 'i-tabler-edit' },
},
Expand Down Expand Up @@ -191,9 +204,9 @@ const options = vue.computed(() => {
actions: () => [
{
name: 'View Settings',
href: card.link(`/settings/project`),
theme: 'theme',
icon: { class: 'i-tabler-arrow-up-right' },
onClick: () => saveBeforeNavigate({ location: 'view-settings', href: card.link(`/settings/project`) }),
},
],
}),
Expand Down Expand Up @@ -330,34 +343,25 @@ async function sendOrSchedule() {
showSendModal.value = false
}
async function saveChanges() {
saving.value = true
campaign?.save()
settingsModal.value = ''
saving.value = false
}
const header = vue.computed(() => {
const em = campaign?.toConfig() as EmailCampaignConfig
const incompleteItems = options.value.filter(opt => opt.valueDisplay.value?.status === 'incomplete')
const allControlOptions = options.value.flatMap(o => [o, ...o.options.value]).filter(o => o.input.value === 'InputControl')
const incompleteItems = allControlOptions.filter(opt => opt.valueDisplay.value?.status === 'incomplete')
const isReady = incompleteItems.length === 0
const isScheduled = em?.scheduleMode === 'schedule'
const actionText = isScheduled ? `Schedule Send` : 'Send'
const statusText = !isReady
? `Edits Required`
: `Ready to ${actionText}`
? `Edits Needed`
: `Ready to Publish`
const actions = [
{
size: 'md',
name: 'Email Composer',
icon: 'i-tabler-edit',
theme: !isReady ? 'primary' : 'theme',
href: getCampaignLink('newsletter-composer'),
onClick: () => saveBeforeNavigate({ location: 'header-composer-link', href: getCampaignLink('newsletter-composer') }),
},
Expand All @@ -367,7 +371,7 @@ const header = vue.computed(() => {
actions.push({
size: 'md',
design: 'textOnly',
name: isReady ? 'Ready' : `${options.value.length - incompleteItems.length} / ${options.value.length} Complete`,
name: isReady ? 'Ready' : `${allControlOptions.length - incompleteItems.length} / ${allControlOptions.length} Complete`,
disabled: true,
})
}
Expand Down Expand Up @@ -396,16 +400,9 @@ const header = vue.computed(() => {
</script>

<template>
<SettingsPanel title="Newletter Email Overview">
<SettingsPanel title="Newletter Email Overview" :header>
<div class="">
<div class="my-6 space-y-6">
<div class="px-8">
<ElHeader
v-if="header"
class="dark:bg-theme-700/50 rounded-xl p-8"
:model-value="header"
/>
</div>
<FormEngine
:model-value="campaign?.toConfig()"
state-key="settingsTool"
Expand Down
17 changes: 11 additions & 6 deletions @fiction/plugins/plugin-newsletter/admin/SidebarEmailEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,17 @@ const options = vue.computed<InputOption[]>(() => {
options: [
new InputOption({ key: 'post.title', label: 'Title', input: 'InputText', placeholder: 'Title', isRequired: true }),
new InputOption({ key: 'post.subTitle', label: 'Subtitle', input: 'InputText' }),
new InputOption({ key: 'userConfig.actions', label: 'Calls to Action', input: 'InputActions', props: {
addOptions: [
new InputOption({ key: 'theme', label: 'Color Theme', input: 'InputSelectCustom', list: ['primary', 'default', 'naked'] }),
],
disableKeys: ['design', 'icon', 'iconAfter', 'target', 'theme', 'size'],
} }),
new InputOption({
key: 'userConfig.actions',
label: 'Calls to Action',
input: 'InputActions',
props: {
addOptions: [
new InputOption({ key: 'theme', label: 'Color Theme', input: 'InputSelectCustom', list: ['primary', 'default', 'naked'] }),
],
disableKeys: ['design', 'icon', 'iconAfter', 'target', 'theme', 'size'],
},
}),
],
}),
Expand Down
29 changes: 21 additions & 8 deletions @fiction/plugins/plugin-newsletter/test/newsletter.flow.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import type { EmailCampaignConfig } from '../schema'
import { dayjs, isCi } from '@fiction/core'
import { createUiTestingKit } from '@fiction/core/test-utils/kit'
import { createSiteUiTestingKit } from '@fiction/site/test/testUtils.js'
import { afterAll, describe, expect, it } from 'vitest'
import { setup } from './kit.main.js'

describe('admin:newsletter', async () => {
const kit = await createUiTestingKit({ headless: false, setup, slowMo: 1000, initUser: true })
const kit = await createUiTestingKit({ headless: false, setup, slowMo: 500, initUser: true })
const testUtils = kit.testUtils

if (!testUtils)
Expand All @@ -24,17 +22,32 @@ describe('admin:newsletter', async () => {
{ type: 'click', selector: `[data-test-id="new-email-button-zero"]` },
{ type: 'fill', selector: `[data-test-id="email-title-input"] input`, text: 'Test Email' },
{ type: 'click', selector: `[data-test-id="step-button-emailTitle"]` },
{ type: 'click', selector: `[data-test-id="email-schedule-edit-button"]` },
{ type: 'click', selector: `[data-option-path="scheduleMode"] [data-input-type="select"]` },
{ type: 'click', selector: `[data-option-path="scheduleMode"] [data-value="schedule"]` },
{ type: 'fill', selector: `[data-option-path="scheduledAt"] input`, text: dayjs().add(1, 'day').format('YYYY-MM-DDTHH:mm') },
{ type: 'click', selector: `[data-test-id="email-schedule-modal-apply"]` },
{ type: 'click', selector: `[data-test-id="email-subject-line-edit-button"]` },
{ type: 'fill', selector: `[data-option-path="subject"] input`, text: 'Test Subject' },
{ type: 'click', selector: `[data-test-id="email-subject-line-modal-apply"]` },
{ type: 'click', selector: `[data-test-id="email-preview-text-edit-button"]` },
{ type: 'fill', selector: `[data-option-path="preview"] input`, text: 'Test Preview Text' },
{ type: 'click', selector: `[data-test-id="email-preview-text-modal-apply"]` },
{ type: 'click', selector: `[data-test-id="email-schedule-edit-button"]` },
{ type: 'click', selector: `[data-option-path="scheduleMode"] [data-input-type="select"]` },
{ type: 'click', selector: `[data-option-path="scheduleMode"] [data-value="schedule"]` },
{ type: 'fill', selector: `[data-option-path="scheduledAt"] input`, text: dayjs().add(1, 'day').format('YYYY-MM-DD') },
{ type: 'click', selector: `[data-test-id="email-schedule-modal-apply"]` },
{ type: 'click', selector: '[data-test-id="email-composer-link"]' },
{ type: 'hasValue', selector: '[data-option-path="subject"] input', text: 'Test Subject' },
{ type: 'hasValue', selector: '[data-option-path="preview"] input', text: 'Test Preview Text' },
{ type: 'fill', selector: '[data-test-id="post-editor-title"]', text: 'Test Content Title' },
{ type: 'fill', selector: '[data-test-id="post-editor-sub-title"]', text: 'Test Content Subtitle' },
{ type: 'hasValue', selector: '[data-option-path="post.title"] input', text: 'Test Content Title' },
{ type: 'hasValue', selector: '[data-option-path="post.subTitle"] input', text: 'Test Content Subtitle' },
{ type: 'fill', selector: '[data-test-id="prose-editor-content"] .tiptap', text: 'welcome to the jungle' },
{ type: 'click', selector: '[data-option-path="userConfig.actions"] button' },
{ type: 'click', selector: '[data-option-path="userConfig.actions"] [data-option-path="theme"] [data-input-type="select"]' },
{ type: 'click', selector: '[data-option-path="userConfig.actions"] [data-index="0"]' },
{ type: 'exists', selector: '[data-test-id="editor-actions"] button' },
{ type: 'click', selector: '[data-test-id="review-send-button"]' },
{ type: 'hasText', selector: '[data-test-id="email-subject-line-display-value"]', text: 'Test Subject' },
{ type: 'hasText', selector: '[data-test-id="email-preview-text-display-value"]', text: 'Test Preview Text' },
// { type: 'click', selector: '[data-test-id="add-subscribers-button"]' },
// { type: 'fill', selector: `[data-test-id="text-email-list"] textarea`, text: '[email protected], [email protected]' },
// { type: 'click', selector: `[data-test-id="save"]` },
Expand Down
7 changes: 4 additions & 3 deletions @fiction/ui/inputs/InputControl.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const emit = defineEmits<{
(event: 'update:modelValue', payload: any): void
}>()
const baseTestId = controlOption.settings.testId || 'input-control'
// needed on option to control outputs/visible of other options
controlOption.tempValue.value = vue.toRaw(modelValue)
Expand Down Expand Up @@ -47,7 +49,6 @@ function cancelChanges() {
const modalActions = vue.computed<ActionButton[]>(() => {
const optionModalActions = controlOption.modalActions.value
const baseTestId = controlOption.settings.testId || 'input-control'
if (!optionModalActions) {
return [
{
Expand All @@ -65,7 +66,6 @@ const modalActions = vue.computed<ActionButton[]>(() => {
const actions = vue.computed<ActionButton[]>(() => {
const optionActions = controlOption.actions.value
const baseTestId = controlOption.settings.testId || 'input-control'
if (!optionActions) {
return [
{
Expand Down Expand Up @@ -100,7 +100,7 @@ const actions = vue.computed<ActionButton[]>(() => {
<div v-else-if="v?.format === 'media' && isPlainObject(v?.data)" class="my-2">
<XMedia class="size-14" :media="(v?.data as MediaObject)" />
</div>
<div v-else>
<div v-else :data-test-id="`${baseTestId}-display-value`">
{{ v?.data || 'Not Set' }}
</div>
</div>
Expand All @@ -113,6 +113,7 @@ const actions = vue.computed<ActionButton[]>(() => {
:icon="v?.status === 'ready' ? 'i-tabler-check' : v?.status === 'incomplete' ? 'i-tabler-x' : 'i-tabler-circle-plus'"
:theme="v?.status === 'ready' ? 'green' : v?.status === 'incomplete' ? 'rose' : 'theme'"
size="md"
:data-test-id="`${baseTestId}-status-button`"
>
{{ toLabel(v?.status) }}
</XButton>
Expand Down
10 changes: 9 additions & 1 deletion @fiction/ui/inputs/InputDate.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,15 @@ const dateFormat = vue.computed(() => {
return props.includeTime ? 'YYYY-MM-DDTHH:mm' : 'YYYY-MM-DD'
})
const inputValue = vue.computed(() => {
return props.modelValue ? dayjs(props.modelValue).format(dateFormat.value) : ''
if (!props.modelValue)
return ''
const date = dayjs(props.modelValue)
if (!date.isValid()) {
return ''
}
return date.format(dateFormat.value)
})
const dateEl = vue.ref<HTMLInputElement>()
Expand Down

0 comments on commit ff2fcff

Please sign in to comment.