import {BillingDetailsFixture} from 'getsentry-test/fixtures/billingDetails'; import {InvoiceFixture} from 'getsentry-test/fixtures/invoice'; import {SubscriptionFixture} from 'getsentry-test/fixtures/subscription'; import {initializeOrg} from 'sentry-test/initializeOrg'; import { render, renderGlobalModal, screen, userEvent, waitFor, } from 'sentry-test/reactTestingLibrary'; import SubscriptionStore from 'getsentry/stores/subscriptionStore'; import {InvoiceItemType} from 'getsentry/types'; import InvoiceDetails from 'getsentry/views/invoiceDetails'; describe('InvoiceDetails', function () { const {organization, router, routerProps} = initializeOrg(); const basicInvoice = InvoiceFixture( { dateCreated: '2021-09-20T22:33:38.042Z', items: [ { type: InvoiceItemType.SUBSCRIPTION, description: 'Subscription to Business', amount: 8900, periodEnd: '2021-10-21', periodStart: '2021-09-21', data: {}, }, ], }, organization ); const creditInvoice = InvoiceFixture( { amount: 8900, amountBilled: 8400, creditApplied: 500, items: [ { type: InvoiceItemType.SUBSCRIPTION, description: 'Subscription to Business', amount: 8900, periodEnd: '2021-10-21', periodStart: '2021-09-21', data: {}, }, { type: InvoiceItemType.CREDIT_APPLIED, description: 'Credit applied', amount: 500, periodEnd: '2021-10-21', periodStart: '2021-09-21', data: {}, }, ], }, organization ); const params = {invoiceGuid: basicInvoice.id}; beforeEach(function () { MockApiClient.clearMockResponses(); SubscriptionStore.set(organization.slug, {}); MockApiClient.addMockResponse({ url: `/customers/${organization.slug}/billing-details/`, method: 'GET', body: {}, }); }); it('renders basic invoice details', async function () { const mockapi = MockApiClient.addMockResponse({ url: `/customers/${organization.slug}/invoices/${basicInvoice.id}/`, method: 'GET', body: basicInvoice, }); render( ); await waitFor(() => expect(mockapi).toHaveBeenCalled()); expect(await screen.findByText('Sentry')).toBeInTheDocument(); expect(screen.getByText(/Subscription to Business/)).toBeInTheDocument(); expect(screen.getByText('Sep 21, 2021')).toBeInTheDocument(); expect(screen.getByText('Oct 21, 2021')).toBeInTheDocument(); expect(screen.getByText('Sep 20, 2021')).toBeInTheDocument(); expect(screen.getByText('$89.00 USD')).toBeInTheDocument(); }); it('renders credit applied', async function () { const mockapi = MockApiClient.addMockResponse({ url: `/customers/${organization.slug}/invoices/${creditInvoice.id}/`, method: 'GET', body: creditInvoice, }); const creditParams = {invoiceGuid: creditInvoice.id}; render( ); await waitFor(() => expect(mockapi).toHaveBeenCalled()); expect(await screen.findByText('Sentry')).toBeInTheDocument(); expect(screen.getByText(/Subscription to Business/)).toBeInTheDocument(); expect(screen.getByText('$89.00 USD')).toBeInTheDocument(); }); it('renders an error', async function () { const mockapi = MockApiClient.addMockResponse({ url: `/customers/${organization.slug}/invoices/${basicInvoice.id}/`, method: 'GET', statusCode: 404, body: {}, }); render(); await waitFor(() => expect(mockapi).toHaveBeenCalled()); expect( await screen.findByText('There was an error loading data.') ).toBeInTheDocument(); }); it('sends a request to email the invoice', async function () { const mockget = MockApiClient.addMockResponse({ url: `/customers/${organization.slug}/invoices/${basicInvoice.id}/`, method: 'GET', statusCode: 200, body: basicInvoice, }); const mockpost = MockApiClient.addMockResponse({ url: `/customers/${organization.slug}/invoices/${basicInvoice.id}/`, method: 'POST', }); render(); await waitFor(() => expect(mockget).toHaveBeenCalled()); const input = await screen.findByPlaceholderText('you@example.com'); await userEvent.type(input, 'user@example.com'); const button = screen.getByText('Email Receipt'); await userEvent.click(button); await waitFor(() => expect(mockpost).toHaveBeenCalled()); expect(mockpost).toHaveBeenCalledWith( `/customers/${organization.slug}/invoices/${basicInvoice.id}/`, expect.objectContaining({ data: {op: 'send_receipt', email: 'user@example.com'}, }) ); // Form should be reset. expect(screen.queryByText('user@example.com')).not.toBeInTheDocument(); }); it('renders with open pay now with billing failure referrer', async function () { router.location = { ...router.location, query: {referrer: 'billing-failure'}, }; const pastDueInvoice = InvoiceFixture( { amount: 8900, isClosed: false, isPaid: false, items: [ { type: InvoiceItemType.SUBSCRIPTION, description: 'Subscription to Business', amount: 8900, periodEnd: '2021-10-21', periodStart: '2021-09-21', data: {}, }, ], }, organization ); const pastDueParams = {invoiceGuid: pastDueInvoice.id}; const mockapiInvoice = MockApiClient.addMockResponse({ url: `/customers/${organization.slug}/invoices/${pastDueInvoice.id}/`, method: 'GET', body: pastDueInvoice, }); const mockapiPayments = MockApiClient.addMockResponse({ url: `/organizations/${organization.slug}/payments/${pastDueInvoice.id}/new/`, method: 'GET', body: {}, }); renderGlobalModal(); render( , { router, } ); await waitFor(() => expect(mockapiInvoice).toHaveBeenCalled()); await waitFor(() => expect(mockapiPayments).toHaveBeenCalled()); expect(screen.getByText(/Invoice Details/)).toBeInTheDocument(); expect(screen.getAllByText(/Pay Now/)).toHaveLength(2); expect(screen.getByText(/Pay Invoice/)).toBeInTheDocument(); expect(screen.getByText(/Card Details/)).toBeInTheDocument(); expect(screen.getByTestId('modal-backdrop')).toBeInTheDocument(); expect(screen.getByTestId('cancel')).toBeInTheDocument(); expect(screen.getByTestId('submit')).toBeInTheDocument(); }); describe('Invoice Details Attributes', function () { const billingDetails = BillingDetailsFixture({taxNumber: '123456789'}); SubscriptionFixture({organization}); beforeEach(function () { MockApiClient.clearMockResponses(); SubscriptionStore.set(organization.slug, {}); MockApiClient.addMockResponse({ url: `/customers/${organization.slug}/billing-details/`, method: 'GET', body: billingDetails, }); }); it('renders with billing address', async function () { const mockInvoice = MockApiClient.addMockResponse({ url: `/customers/${organization.slug}/invoices/${basicInvoice.id}/`, method: 'GET', body: basicInvoice, }); render(); await waitFor(() => expect(mockInvoice).toHaveBeenCalled()); expect( await screen.findByText(`${billingDetails.companyName}`) ).toBeInTheDocument(); expect(screen.getByText('Details:')).toBeInTheDocument(); expect(screen.getByText(`${billingDetails.displayAddress}`)).toBeInTheDocument(); expect(screen.getByText('Tax Number:')).toBeInTheDocument(); expect(screen.getByText(`${billingDetails.taxNumber}`)).toBeInTheDocument(); expect(screen.getByText(`${billingDetails.billingEmail}`)).toBeInTheDocument(); expect(screen.queryByText('Country Id: 1234')).not.toBeInTheDocument(); expect(screen.queryByText('Regional Tax Id: 5678')).not.toBeInTheDocument(); }); it('renders sentry tax ids', async function () { const basicInvoiceWithSentryTaxIds = InvoiceFixture( { sentryTaxIds: { taxId: '1234', taxIdName: 'Country Id', region: { code: 'AA', taxId: '5678', taxIdName: 'Regional Tax Id', }, }, }, organization ); const mockInvoice = MockApiClient.addMockResponse({ url: `/customers/${organization.slug}/invoices/${basicInvoiceWithSentryTaxIds.id}/`, method: 'GET', body: basicInvoiceWithSentryTaxIds, }); render(); await waitFor(() => expect(mockInvoice).toHaveBeenCalled()); expect(await screen.findByText('Country Id: 1234')).toBeInTheDocument(); expect(screen.getByText('Regional Tax Id: 5678')).toBeInTheDocument(); }); it('renders reverse charge row', async function () { const basicInvoiceReverseCharge = InvoiceFixture( { isReverseCharge: true, defaultTaxName: 'VAT', }, organization ); const mockInvoice = MockApiClient.addMockResponse({ url: `/customers/${organization.slug}/invoices/${basicInvoiceReverseCharge.id}/`, method: 'GET', body: basicInvoiceReverseCharge, }); render(); await waitFor(() => expect(mockInvoice).toHaveBeenCalled()); expect(await screen.findByText('VAT')).toBeInTheDocument(); expect(screen.getByText('Reverse Charge')).toBeInTheDocument(); }); }); });