cover SMTP authentication and revert campaign date changes

This commit is contained in:
Abhinav Raut
2026-10-21 02:10:40 +05:30
parent da8ee1693a
commit 64b4424251
4 changed files with 61 additions and 63 deletions
@@ -102,8 +102,8 @@ const businessHours = ref([])
const error = ref('')
const pendingDelete = ref(null)
const stats = ref([])
const from = ref('')
const to = ref('')
const from = ref(new Date(Date.now() - 30 * 86400000).toISOString().slice(0, 10))
const to = ref(new Date().toISOString().slice(0, 10))
const brandSenderName = computed(() => props.brandName.trim() || t('widget.brandBot'))
const campaignEventExample = computed(
() => `window.Libredesk.trackEvent(${JSON.stringify(campaign.value?.event || 'pricing_viewed')})`
@@ -285,26 +285,13 @@ const refreshStats = async () => {
}
onMounted(async () => {
const [hoursResult, settingsResult] = await Promise.allSettled([
api.getAllBusinessHours(),
api.getSettings('general')
])
if (hoursResult.status === 'fulfilled') {
const data = hoursResult.value.data.data
try {
const response = await api.getAllBusinessHours()
const data = response.data.data
businessHours.value = data.results || data
} catch (err) {
error.value = handleHTTPError(err).message
}
const failed = [hoursResult, settingsResult].find((result) => result.status === 'rejected')
if (failed) error.value = handleHTTPError(failed.reason).message
const dateFormat = new Intl.DateTimeFormat('en-CA', {
timeZone:
(settingsResult.status === 'fulfilled' && settingsResult.value.data.data['app.timezone']) ||
'UTC',
year: 'numeric',
month: '2-digit',
day: '2-digit'
})
from.value = dateFormat.format(new Date(Date.now() - 30 * 86400000))
to.value = dateFormat.format(new Date())
await refreshStats()
})
</script>
+23 -2
View File
@@ -140,8 +140,13 @@ describe('Email inbox form', () => {
cy.contains('New support inbox').should('be.visible')
})
for (const protocol of ['None', 'Login']) {
it(`validates empty SMTP credentials with ${protocol} authentication`, () => {
for (const [protocol, value] of [
['None', 'none'],
['Login', 'login'],
['CRAM', 'cram'],
['Plain', 'plain']
]) {
it(`validates and saves SMTP credentials with ${protocol} authentication`, () => {
openManualForm()
fillRequiredFields()
field('smtp.username').clear()
@@ -160,6 +165,22 @@ describe('Email inbox form', () => {
cy.get('@createInbox.all').should('have.length', 0)
field('smtp.username').parent().parent().should('contain.text', 'Required')
field('smtp.password').parent().parent().should('contain.text', 'Required')
field('smtp.username').type('support@example.com')
submit()
field('smtp.password').should('have.attr', 'aria-invalid', 'true')
cy.get('@createInbox.all').should('have.length', 0)
field('smtp.username').clear()
field('smtp.password').type('test-password')
submit()
field('smtp.username').should('have.attr', 'aria-invalid', 'true')
cy.get('@createInbox.all').should('have.length', 0)
field('smtp.username').type('support@example.com')
submit()
cy.wait('@createInbox').then(({ request }) => {
expect(request.body.config.smtp[0].auth_protocol).to.eq(value)
expect(request.body.config.smtp[0].username).to.eq('support@example.com')
expect(request.body.config.smtp[0].password).to.eq('test-password')
})
}
})
}
@@ -300,45 +300,6 @@ describe('Live chat inbox form: branches the other specs skip', () => {
})
})
for (const { name, path, message, skipBootCall } of [
{ name: 'settings', path: 'settings/general', message: 'Settings unavailable', skipBootCall: true },
{ name: 'business hours', path: 'business-hours', message: 'Business hours unavailable', skipBootCall: false }
]) {
it(`loads proactive message stats when the ${name} request fails`, () => {
cy.intercept('GET', `**/api/v1/${path}`, {
statusCode: 500,
body: { status: 'error', message, error_type: 'GeneralException', data: null }
})
// The app loads general settings once at boot, before the form mounts. Only later calls fail.
if (skipBootCall) {
cy.intercept({ method: 'GET', url: `**/api/v1/${path}`, times: 1 }, (req) => req.continue())
}
cy.intercept('GET', `**/api/v1/inboxes/${inboxId}/campaign-stats*`).as('campaignStats')
editInbox(inboxId)
cy.wait('@campaignStats').then(({ request, response }) => {
expect(response.statusCode).to.eq(200)
expect(new URL(request.url).searchParams.get('from')).to.match(/^\d{4}-\d{2}-\d{2}$/)
})
cy.contains('[role="alert"]', message).should('exist')
})
}
it('uses workspace dates for campaign statistics across a UTC day boundary', () => {
cy.clock(Date.UTC(2026, 0, 1, 23, 30), ['Date'])
cy.intercept('GET', '**/api/v1/settings/general', (req) => {
req.continue((res) => { res.body.data['app.timezone'] = 'Pacific/Kiritimati' })
})
cy.intercept('GET', `**/api/v1/inboxes/${inboxId}/campaign-stats*`).as('workspaceStats')
editInbox(inboxId)
cy.wait('@workspaceStats').then(({ request, response }) => {
expect(response.statusCode).to.eq(200)
const params = new URL(request.url).searchParams
expect(params.get('from')).to.eq('2025-12-03')
expect(params.get('to')).to.eq('2026-01-02')
})
})
it('saves a proactive message condition and removes it again', () => {
cy.intercept('PUT', `**/api/v1/inboxes/${inboxId}`).as('updateInbox')
@@ -148,8 +148,13 @@ describe('Notification settings form', () => {
cy.get('@saveNotification.all').should('have.length', 0)
})
for (const protocol of ['None', 'Login']) {
it(`validates empty notification SMTP credentials with ${protocol} authentication`, () => {
for (const [protocol, value] of [
['None', 'none'],
['Login', 'login'],
['CRAM-MD5', 'cram'],
['Plain', 'plain']
]) {
it(`validates and saves notification SMTP credentials with ${protocol} authentication`, () => {
cy.intercept('PUT', '**/api/v1/settings/notifications/email').as('saveNotification')
cy.visit(path)
cy.get('input[name="host"]').should('not.have.value', '')
@@ -169,6 +174,30 @@ describe('Notification settings form', () => {
cy.get('@saveNotification.all').should('have.length', 0)
cy.get('input[name="username"]').parent().parent().should('contain.text', 'Required')
cy.get('input[name="password"]').parent().parent().should('contain.text', 'Required')
cy.get('input[name="username"]').type(seedUsername)
cy.get('button[type="submit"]').click()
cy.get('input[name="password"]').should('have.attr', 'aria-invalid', 'true')
cy.get('@saveNotification.all').should('have.length', 0)
cy.get('input[name="username"]').clear()
cy.get('input[name="password"]').type('test-password')
cy.get('button[type="submit"]').click()
cy.get('input[name="username"]').should('have.attr', 'aria-invalid', 'true')
cy.get('@saveNotification.all').should('have.length', 0)
cy.get('input[name="username"]').type(seedUsername)
cy.get('button[type="submit"]').click()
cy.wait('@saveNotification').then(({ request, response }) => {
expect(response.statusCode).to.eq(200)
expect(request.body[`${prefix}auth_protocol`]).to.eq(value)
expect(request.body[`${prefix}username`]).to.eq(seedUsername)
expect(request.body[`${prefix}password`]).to.eq('test-password')
})
cy.reload()
cy.contains('label', 'Authentication Protocol')
.parent()
.find('[role="combobox"]')
.should('contain.text', protocol)
cy.get('input[name="username"]').should('have.value', seedUsername)
cy.get('input[name="password"]').should('have.value', maskedPassword)
}
})
}