123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472 |
- // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- import { getNode } from '@formkit/core'
- import { waitFor, within } from '@testing-library/vue'
- import ticketCustomerObjectAttributes from '#tests/graphql/factories/fixtures/ticket-customer-object-attributes.ts'
- import { visitView } from '#tests/support/components/visitView.ts'
- import { mockApplicationConfig } from '#tests/support/mock-applicationConfig.ts'
- import { mockPermissions } from '#tests/support/mock-permissions.ts'
- import { waitForNextTick } from '#tests/support/utils.ts'
- import { waitForFormUpdaterQueryCalls } from '#shared/components/Form/graphql/queries/formUpdater.mocks.ts'
- import { mockObjectManagerFrontendAttributesQuery } from '#shared/entities/object-attributes/graphql/queries/objectManagerFrontendAttributes.mocks.ts'
- import { waitForTicketCreateMutationCalls } from '#shared/entities/ticket/graphql/mutations/create.mocks.ts'
- import { waitForTicketSharedDraftStartCreateMutationCalls } from '#shared/entities/ticket-shared-draft-start/graphql/mutations/ticketSharedDraftStartCreate.mocks.ts'
- import { waitForTicketSharedDraftStartDeleteMutationCalls } from '#shared/entities/ticket-shared-draft-start/graphql/mutations/ticketSharedDraftStartDelete.mocks.ts'
- import { waitForTicketSharedDraftStartUpdateMutationCalls } from '#shared/entities/ticket-shared-draft-start/graphql/mutations/ticketSharedDraftStartUpdate.mocks.ts'
- import {
- mockTicketSharedDraftStartListQuery,
- waitForTicketSharedDraftStartListQueryCalls,
- } from '#shared/entities/ticket-shared-draft-start/graphql/queries/ticketSharedDraftStartList.mocks.ts'
- import {
- mockTicketSharedDraftStartSingleQuery,
- waitForTicketSharedDraftStartSingleQueryCalls,
- } from '#shared/entities/ticket-shared-draft-start/graphql/queries/ticketSharedDraftStartSingle.mocks.ts'
- import { getTicketSharedDraftStartUpdateByGroupSubscriptionHandler } from '#shared/entities/ticket-shared-draft-start/graphql/subscriptions/ticketSharedDraftStartUpdateByGroup.mocks.ts'
- import {
- convertToGraphQLId,
- getIdFromGraphQLId,
- } from '#shared/graphql/utils.ts'
- import { handleMockFormUpdaterQuery } from '#desktop/pages/ticket/__tests__/support/ticket-create-helpers.ts'
- vi.hoisted(() => {
- vi.setSystemTime('2024-07-03T13:48:09Z')
- })
- describe('ticket create view - shared drafts sidebar', async () => {
- describe('with agent permissions', async () => {
- beforeEach(() => {
- mockApplicationConfig({
- ui_ticket_create_available_types: [
- 'phone-in',
- 'phone-out',
- 'email-out',
- ],
- })
- mockPermissions(['ticket.agent'])
- handleMockFormUpdaterQuery()
- })
- it('supports creating shared drafts', async () => {
- const view = await visitView('/ticket/create')
- await view.events.type(
- await view.findByLabelText('Text'),
- 'foobar<div data-signature="true">Signature here</div>',
- )
- const formUpdaterCalls = await waitForFormUpdaterQueryCalls()
- await vi.waitUntil(() => formUpdaterCalls.length === 2)
- mockTicketSharedDraftStartListQuery({
- ticketSharedDraftStartList: [],
- })
- await view.events.click(view.getByLabelText('Group'))
- await view.events.click(view.getByRole('option', { name: 'Users' }))
- await waitForTicketSharedDraftStartListQueryCalls()
- const aside = within(
- view.getByRole('complementary', {
- name: 'Content sidebar',
- }),
- )
- await view.events.type(
- aside.getByLabelText('Create a shared draft'),
- 'Test shared draft 1',
- )
- await getNode('sharedDraftTitle')?.settled
- await view.events.click(
- aside.getByRole('link', { name: 'Create Shared Draft' }),
- )
- const calls = await waitForTicketSharedDraftStartCreateMutationCalls()
- expect(calls.at(-1)?.variables).toEqual({
- name: 'Test shared draft 1',
- input: expect.objectContaining({
- groupId: convertToGraphQLId('Group', 1),
- content: expect.objectContaining({
- body: 'foobar',
- }),
- }),
- })
- expect(view.getByRole('alert')).toHaveTextContent(
- 'Shared draft has been created successfully.',
- )
- await getTicketSharedDraftStartUpdateByGroupSubscriptionHandler().trigger(
- {
- ticketSharedDraftStartUpdateByGroup: {
- sharedDraftStarts: [
- {
- id: convertToGraphQLId('Ticket::SharedDraftStart', 1),
- name: 'Test shared draft 1',
- updatedAt: '2024-07-03T13:48:09Z',
- updatedBy: {
- fullname: 'Erika Mustermann',
- },
- },
- ],
- },
- },
- )
- await waitForNextTick()
- expect(
- aside.getByRole('link', { name: 'Test shared draft 1' }),
- ).toBeInTheDocument()
- })
- it('supports applying shared drafts', async () => {
- const view = await visitView('/ticket/create')
- const draftToMock = {
- id: convertToGraphQLId('Ticket::SharedDraftStart', 1),
- name: 'Test shared draft 1',
- content: {
- title: 'foobar',
- customer_id: 'test@example.com',
- body: 'body',
- },
- updatedAt: '2024-07-03T13:48:09Z',
- updatedBy: {
- fullname: 'Erika Mustermann',
- },
- }
- mockTicketSharedDraftStartListQuery({
- ticketSharedDraftStartList: [draftToMock],
- })
- await view.events.click(await view.findByLabelText('Group'))
- await view.events.click(view.getByRole('option', { name: 'Users' }))
- await waitForTicketSharedDraftStartListQueryCalls()
- const aside = within(
- view.getByRole('complementary', {
- name: 'Content sidebar',
- }),
- )
- mockTicketSharedDraftStartSingleQuery({
- ticketSharedDraftStartSingle: draftToMock,
- })
- await view.events.click(
- aside.getByRole('link', { name: draftToMock.name }),
- )
- await waitForTicketSharedDraftStartSingleQueryCalls()
- const flyout = within(
- view.getByRole('complementary', {
- name: 'Preview Shared Draft',
- }),
- )
- expect(
- flyout.getByText(draftToMock.updatedBy.fullname),
- ).toBeInTheDocument()
- expect(flyout.getByText('just now')).toBeInTheDocument()
- expect(flyout.getByText(draftToMock.content.body)).toBeInTheDocument()
- await view.events.click(flyout.getByRole('button', { name: 'Apply' }))
- expect(
- await view.findByRole('dialog', { name: 'Apply Draft' }),
- ).toBeInTheDocument()
- const dialog = within(
- view.getByRole('dialog', {
- name: 'Apply Draft',
- }),
- )
- handleMockFormUpdaterQuery({
- title: { value: draftToMock.content.title },
- customer_id: {
- value: draftToMock.content.customer_id,
- options: [{ value: draftToMock.content.customer_id }],
- },
- body: { value: draftToMock.content.body },
- pending_time: { show: false },
- shared_draft_id: { value: getIdFromGraphQLId(draftToMock.id) },
- })
- await view.events.click(
- dialog.getByRole('button', { name: 'Overwrite Content' }),
- )
- await waitFor(() => {
- expect(
- view.queryByRole('dialog', {
- name: 'Apply Draft',
- }),
- ).not.toBeInTheDocument()
- })
- const formUpdaterCalls = await waitForFormUpdaterQueryCalls()
- expect(formUpdaterCalls.at(-1)?.variables).toEqual(
- expect.objectContaining({
- meta: expect.objectContaining({
- additionalData: expect.objectContaining({
- sharedDraftId: draftToMock.id,
- draftType: 'start',
- }),
- }),
- }),
- )
- await waitForNextTick()
- expect(view.getByLabelText('Title')).toHaveValue(
- draftToMock.content.title,
- )
- await view.events.click(view.getByRole('button', { name: 'Create' }))
- const ticketCreateCalls = await waitForTicketCreateMutationCalls()
- expect(ticketCreateCalls.at(-1)?.variables).toEqual(
- expect.objectContaining({
- input: expect.objectContaining({
- title: draftToMock.content.title,
- sharedDraftId: draftToMock.id,
- }),
- }),
- )
- })
- it('supports updating shared drafts', async () => {
- const view = await visitView('/ticket/create')
- mockTicketSharedDraftStartListQuery({
- ticketSharedDraftStartList: [
- {
- id: convertToGraphQLId('Ticket::SharedDraftStart', 1),
- name: 'Test shared draft 1',
- updatedAt: '2024-07-03T13:48:09Z',
- updatedBy: {
- fullname: 'Erika Mustermann',
- },
- },
- ],
- })
- await view.events.click(await view.findByLabelText('Group'))
- await view.events.click(view.getByRole('option', { name: 'Users' }))
- await waitForTicketSharedDraftStartListQueryCalls()
- const aside = within(
- view.getByRole('complementary', {
- name: 'Content sidebar',
- }),
- )
- mockTicketSharedDraftStartSingleQuery({
- ticketSharedDraftStartSingle: {
- name: 'Test shared draft 1',
- content: {
- body: 'foobar',
- },
- updatedAt: '2024-07-03T13:48:09Z',
- updatedBy: {
- fullname: 'Erika Mustermann',
- },
- },
- })
- await view.events.click(
- aside.getByRole('link', { name: 'Test shared draft 1' }),
- )
- await waitForTicketSharedDraftStartSingleQueryCalls()
- const flyout = within(
- view.getByRole('complementary', {
- name: 'Preview Shared Draft',
- }),
- )
- await view.events.click(flyout.getByRole('button', { name: 'Apply' }))
- const dialog = within(
- await view.findByRole('dialog', { name: 'Apply Draft' }),
- )
- handleMockFormUpdaterQuery({
- shared_draft_id: {
- value: 1,
- },
- body: {
- value: 'foobar',
- },
- })
- await view.events.click(
- dialog.getByRole('button', { name: 'Overwrite Content' }),
- )
- await waitFor(() => {
- expect(
- view.queryByRole('complementary', {
- name: 'Preview Shared Draft',
- }),
- ).not.toBeInTheDocument()
- })
- await view.events.click(
- aside.getByRole('button', { name: 'Update Shared Draft' }),
- )
- const calls = await waitForTicketSharedDraftStartUpdateMutationCalls()
- expect(calls.at(-1)?.variables).toEqual({
- sharedDraftId: convertToGraphQLId('Ticket::SharedDraftStart', 1),
- input: expect.objectContaining({
- content: expect.objectContaining({
- body: 'foobar',
- }),
- }),
- })
- expect(view.getByRole('alert')).toHaveTextContent(
- 'Shared draft has been updated successfully.',
- )
- expect(
- aside.getByRole('button', { name: 'Update Shared Draft' }),
- ).toBeInTheDocument()
- })
- it('supports deleting shared drafts', async () => {
- const view = await visitView('/ticket/create')
- mockTicketSharedDraftStartListQuery({
- ticketSharedDraftStartList: [
- {
- id: convertToGraphQLId('Ticket::SharedDraftStart', 1),
- name: 'Test shared draft 1',
- updatedAt: '2024-07-03T13:48:09Z',
- updatedBy: {
- fullname: 'Erika Mustermann',
- },
- },
- ],
- })
- await view.events.click(await view.findByLabelText('Group'))
- await view.events.click(view.getByRole('option', { name: 'Users' }))
- await waitForTicketSharedDraftStartListQueryCalls()
- const aside = within(
- view.getByRole('complementary', {
- name: 'Content sidebar',
- }),
- )
- mockTicketSharedDraftStartSingleQuery({
- ticketSharedDraftStartSingle: {
- name: 'Test shared draft 1',
- content: {
- body: 'foobar',
- },
- updatedAt: '2024-07-03T13:48:09Z',
- updatedBy: {
- fullname: 'Erika Mustermann',
- },
- },
- })
- await view.events.click(
- aside.getByRole('link', { name: 'Test shared draft 1' }),
- )
- await waitForTicketSharedDraftStartSingleQueryCalls()
- const flyout = within(
- view.getByRole('complementary', {
- name: 'Preview Shared Draft',
- }),
- )
- await view.events.click(flyout.getByRole('button', { name: 'Delete' }))
- const dialog = within(
- await view.findByRole('dialog', { name: 'Delete Object' }),
- )
- await view.events.click(
- dialog.getByRole('button', { name: 'Delete Object' }),
- )
- const calls = await waitForTicketSharedDraftStartDeleteMutationCalls()
- expect(calls.at(-1)?.variables).toEqual({
- sharedDraftId: convertToGraphQLId('Ticket::SharedDraftStart', 1),
- })
- await waitFor(() => {
- expect(
- view.queryByRole('complementary', {
- name: 'Preview Shared Draft',
- }),
- ).not.toBeInTheDocument()
- })
- // FIXME: Check why returning an empty array triggers the following console error in test environment only.
- // Cache data may be lost when replacing the ticketSharedDraftStartList field of a Query object.
- await getTicketSharedDraftStartUpdateByGroupSubscriptionHandler().trigger(
- {
- ticketSharedDraftStartUpdateByGroup: {},
- },
- )
- expect(
- aside.queryByRole('link', { name: 'Test shared draft 1' }),
- ).not.toBeInTheDocument()
- })
- })
- describe('with customer permission', () => {
- beforeEach(() => {
- mockApplicationConfig({
- customer_ticket_create: true,
- })
- mockPermissions(['ticket.customer'])
- // Mock frontend attributes for customer context.
- // TODO: check if we can mock the query twice based on the variable?
- mockObjectManagerFrontendAttributesQuery({
- objectManagerFrontendAttributes: ticketCustomerObjectAttributes(),
- })
- handleMockFormUpdaterQuery()
- })
- it('does not show', async () => {
- const view = await visitView('/ticket/create')
- await view.events.click(await view.findByLabelText('Group'))
- await view.events.click(view.getByRole('option', { name: 'Users' }))
- await waitForFormUpdaterQueryCalls()
- expect(
- view.queryByRole('complementary', {
- name: 'Content sidebar',
- }),
- ).not.toBeInTheDocument()
- })
- })
- })
|