Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added warning if flow is not published #3142

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 43 additions & 13 deletions src/components/floweditor/FlowEditor.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BrowserRouter as Router } from 'react-router-dom';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import { MockedProvider } from '@apollo/client/testing';
import { render, waitFor, fireEvent, screen } from '@testing-library/react';
import { vi } from 'vitest';
Expand All @@ -15,6 +15,7 @@
resetFlowCount,
getFlowTranslations,
getTemplateFlow,
unsavedFlow,
} from 'mocks/Flow';
import { conversationQuery } from 'mocks/Chat';
import {
Expand All @@ -29,20 +30,19 @@

window.location = { assign: vi.fn() } as any;

vi.mock('react-router-dom', async () => {
return {
...(await vi.importActual<any>('react-router-dom')),
useParams: () => ({ uuid: 'b050c652-65b5-4ccf-b62b-1e8b3f328676' }),
};
});

vi.mock('axios');
const mockedAxios = axios as any;

vi.mock('../simulator/Simulator', () => ({
default: ({ message }: { message: string }) => <div data-testid="simulator">{message}</div>, // Mocking the component's behavior
}));

const mockedUsedNavigate = vi.fn();
vi.mock('react-router-dom', async () => ({
...(await vi.importActual('react-router-dom')),
useNavigate: () => mockedUsedNavigate,
}));

const mocks = [
messageReceivedSubscription({ organizationId: null }),
messageSendSubscription({ organizationId: null }),
Expand All @@ -60,16 +60,19 @@
getFlowTranslations,
];

const activeFlowMocks = [...mocks, getActiveFlow];
const activeFlowMocks = [...mocks, getActiveFlow, getActiveFlow];
const inActiveFlowMocks = [...mocks, getInactiveFlow];
const noKeywordMocks = [...mocks, getFlowWithoutKeyword, resetFlowCount];
const templateFlowMocks = [...mocks, getTemplateFlow, resetFlowCount];
const flowWithUnsavedChanges = [...mocks, unsavedFlow, unsavedFlow];

const wrapperFunction = (mocks: any) => (
const wrapperFunction = (mocks: any, uuid: string = 'b050c652-65b5-4ccf-b62b-1e8b3f328676') => (
<MockedProvider mocks={mocks} addTypename={false}>
<Router>
<FlowEditor />
</Router>
<MemoryRouter initialEntries={[`/flow/configure/${uuid}`]}>
<Routes>
<Route path="flow/configure/:uuid" element={<FlowEditor />} />
</Routes>
</MemoryRouter>
</MockedProvider>
);

Expand All @@ -95,6 +98,12 @@
await waitFor(() => {
expect(getByTestId('back-button')).toBeInTheDocument();
});

fireEvent.click(getByTestId('back-button'));

await waitFor(() => {
expect(mockedUsedNavigate).toHaveBeenCalled();
});
});

test('it should display name of the flow', async () => {
Expand Down Expand Up @@ -220,7 +229,7 @@
});
fireEvent.click(screen.getByTestId('previewButton'));
await waitFor(() => {
expect(screen.findByTestId('beneficiaryName'));

Check failure on line 232 in src/components/floweditor/FlowEditor.test.tsx

View workflow job for this annotation

GitHub Actions / CI

Unhandled error

TestingLibraryElementError: Unable to find an element by: [data-testid="beneficiaryName"] Ignored nodes: comments, script, style <body style="" > <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> </body> Ignored nodes: comments, script, style <body style="" > <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> <link href="/static/css/main.671055c3.chunk.css" id="flowEditorfile0" rel="stylesheet" /> </body> ❯ waitForWrapper node_modules/@testing-library/dom/dist/wait-for.js:163:27 ❯ node_modules/@testing-library/dom/dist/query-helpers.js:86:33 ❯ src/components/floweditor/FlowEditor.test.tsx:232:19 ❯ runWithExpensiveErrorDiagnosticsDisabled node_modules/@testing-library/dom/dist/config.js:47:12 ❯ checkCallback node_modules/@testing-library/dom/dist/wait-for.js:124:77 ❯ node_modules/@testing-library/dom/dist/wait-for.js:97:7 ❯ waitFor node_modules/@testing-library/dom/dist/wait-for.js:36:10 ❯ node_modules/@testing-library/dom/dist/wait-for.js:164:54 ❯ Object.asyncWrapper node_modules/@testing-library/react/dist/pure.js:88:28 This error originated in "src/components/floweditor/FlowEditor.test.tsx" test file. It doesn't mean the error was thrown inside the file itself, but while it was running.
});

await waitFor(() => {
Expand Down Expand Up @@ -313,4 +322,25 @@
await waitFor(() => {
expect(screen.getByTestId('simulator')).toHaveTextContent('template:help workflow');
});

fireEvent.click(screen.getByTestId('back-button'));

await waitFor(() => {
expect(mockedUsedNavigate).toHaveBeenCalled();
});
});

test('if flow is not published it should show warning', async () => {
const { getByTestId } = render(wrapperFunction(flowWithUnsavedChanges, '63397051-789d-418d-9388-2ef7eb1268bb'));

await waitFor(() => {
expect(getByTestId('back-button')).toBeInTheDocument();
});

fireEvent.click(getByTestId('back-button'));

await waitFor(() => {
expect(screen.getByTestId('dialogBox')).toBeInTheDocument();
});
fireEvent.click(getByTestId('cancel-button'));
});
86 changes: 45 additions & 41 deletions src/components/floweditor/FlowEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const FlowEditor = () => {
const params = useParams();
const { uuid } = params;
const navigate = useNavigate();
const [publishDialog, setPublishDialog] = useState(false);
const [publishDialog, setPublishDialog] = useState<string | null>(null);
const [loading, setLoading] = useState(true);
const [flowEditorLoaded, setFlowEditorLoaded] = useState(false);
const [flowId, setFlowId] = useState();
Expand Down Expand Up @@ -127,7 +127,7 @@ export const FlowEditor = () => {
},
});

const { data: flowName } = useQuery(GET_FLOW_DETAILS, {
const { data: flowData, refetch } = useQuery(GET_FLOW_DETAILS, {
fetchPolicy: 'network-only',
variables: {
filter: {
Expand All @@ -138,15 +138,15 @@ export const FlowEditor = () => {
});

useEffect(() => {
if (flowName && flowName.flows.length > 0) {
setFlowId(flowName.flows[0].id);
setIsTemplate(flowName.flows[0].isTemplate);
if (flowData && flowData.flows.length > 0) {
setFlowId(flowData.flows[0].id);
setIsTemplate(flowData.flows[0].isTemplate);
}
}, [flowName]);
}, [flowData]);

if (flowName && flowName.flows.length > 0) {
flowTitle = flowName.flows[0].name;
flowKeywords = flowName.flows[0].keywords.join(', ');
if (flowData && flowData.flows.length > 0) {
flowTitle = flowData.flows[0].name;
flowKeywords = flowData.flows[0].keywords.join(', ');
}

const handleResetFlowCount = () => {
Expand All @@ -167,31 +167,25 @@ export const FlowEditor = () => {
additionalTitleStyles={styles.DialogTitle}
>
<div className={styles.DialogContent}>
Please be careful, this cannot be undone. Once you reset the flow counts you will lose
tracking of how many times a node was triggered for users.
Please be careful, this cannot be undone. Once you reset the flow counts you will lose tracking of how many
times a node was triggered for users.
</div>
</DialogBox>
);
}

if (showTranslateFlowModal) {
modal = (
<FlowTranslation
loadFlowEditor={loadFlowEditor}
flowId={flowId}
setDialog={setShowTranslateFlowModal}
/>
);
modal = <FlowTranslation loadFlowEditor={loadFlowEditor} flowId={flowId} setDialog={setShowTranslateFlowModal} />;
}

useEffect(() => {
if (flowName) {
if (flowData) {
document.title = flowTitle;
}
return () => {
document.title = APP_NAME;
};
}, [flowName]);
}, [flowData]);

useEffect(() => {
if (flowId) {
Expand Down Expand Up @@ -234,7 +228,7 @@ export const FlowEditor = () => {
};

const handleCancelFlow = () => {
setPublishDialog(false);
setPublishDialog(null);
setIsError(false);
setFlowValidation('');
};
Expand Down Expand Up @@ -267,8 +261,7 @@ export const FlowEditor = () => {
}}
>
<p className={styles.DialogDescription}>
You can either go back and edit it later or <br /> &lsquo;Take Over&rsquo; this flow to
start editing now.
You can either go back and edit it later or <br /> &lsquo;Take Over&rsquo; this flow to start editing now.
</p>
</DialogBox>
);
Expand All @@ -277,7 +270,7 @@ export const FlowEditor = () => {
if (publishDialog) {
dialog = (
<DialogBox
title="Ready to publish?"
title={publishDialog === 'publish' ? 'Publish flow' : 'Unsaved changes.'}
buttonOk="Publish & stay"
titleAlign="center"
buttonOkLoading={publishLoading}
Expand All @@ -296,7 +289,11 @@ export const FlowEditor = () => {
buttonCancel="Cancel"
additionalTitleStyles={styles.PublishDialogTitle}
>
<p className={styles.DialogDescription}>New changes will be activated for the users</p>
<p className={styles.DialogDescription}>
{publishDialog === 'publish'
? 'New changes will be activated for the users'
: 'You have unsaved changes. Do you want to publish the flow before exiting?'}
</p>
</DialogBox>
);
}
Expand All @@ -307,7 +304,7 @@ export const FlowEditor = () => {
title="Errors were detected in the flow. Would you like to continue modifying?"
buttonOk="Publish"
handleOk={() => {
setPublishDialog(false);
setPublishDialog(null);
setIsError(false);
setPublished(true);
}}
Expand All @@ -325,12 +322,12 @@ export const FlowEditor = () => {
if (!stayOnPublish) {
return <Navigate to="/flow" />;
}
setPublishDialog(false);
setPublishDialog(null);
setPublished(false);
}

const getFlowKeyword = () => {
const flows = flowName ? flowName.flows : null;
const flows = flowData ? flowData.flows : null;
if (flows && flows.length > 0) {
const { isActive, keywords, isTemplate, name } = flows[0];
if (isTemplate) {
Expand All @@ -345,20 +342,32 @@ export const FlowEditor = () => {
}
};

const handleBack = async () => {
if (isTemplate) {
navigate('/flow?isTemplate=true');
return;
}

refetch().then(({ data }) => {
const isFlowPublished = data.flows[0].lastChangedAt === null;
if (isFlowPublished) {
navigate('/flow');
} else {
setPublishDialog('unsaved');
}
});
};

return (
<>
{exportFlowloading && <BackdropLoader />}
{dialog}
<div className={styles.Header}>
<div className={styles.Title}>
<BackIconFlow
onClick={() => (isTemplate ? navigate('/flow?isTemplate=true') : navigate('/flow'))}
className={styles.BackIcon}
data-testid="back-button"
/>
<BackIconFlow onClick={handleBack} className={styles.BackIcon} data-testid="back-button" />
<div>
<Typography variant="h6" data-testid="flowName">
{flowName ? flowTitle : 'Flow'}
{flowData ? flowTitle : 'Flow'}
</Typography>
<div>{flowKeywords}</div>
</div>
Expand Down Expand Up @@ -436,7 +445,7 @@ export const FlowEditor = () => {
color="primary"
data-testid="button"
disabled={isTemplate}
onClick={() => setPublishDialog(true)}
onClick={() => setPublishDialog('publish')}
>
<PublishIcon className={styles.Icon} />
Publish
Expand All @@ -445,12 +454,7 @@ export const FlowEditor = () => {
</div>

{showSimulator && (
<Simulator
setShowSimulator={setShowSimulator}
hasResetButton
flowSimulator
message={getFlowKeyword()}
/>
<Simulator setShowSimulator={setShowSimulator} hasResetButton flowSimulator message={getFlowKeyword()} />
)}
{modal}
<div className={styles.FlowContainer}>
Expand Down
2 changes: 2 additions & 0 deletions src/graphql/queries/Flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export const GET_FLOW_DETAILS = gql`
name
keywords
isTemplate
lastPublishedAt
lastChangedAt
}
}
`;
Expand Down
25 changes: 16 additions & 9 deletions src/mocks/Flow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -268,12 +268,12 @@ export const filterFlowWithNameOrKeywordOrTagQuery = {
},
};

const getFlowDetails = (isActive = true, keywords = ['help'], isTemplate = false) => ({
const getFlowDetails = (data?: any, uuid: string = 'b050c652-65b5-4ccf-b62b-1e8b3f328676') => ({
request: {
query: GET_FLOW_DETAILS,
variables: {
filter: {
uuid: 'b050c652-65b5-4ccf-b62b-1e8b3f328676',
uuid,
},
opts: {},
},
Expand All @@ -284,20 +284,27 @@ const getFlowDetails = (isActive = true, keywords = ['help'], isTemplate = false
flows: [
{
id: '1',
isActive,
name: 'help workflow',
keywords,
isTemplate,
isActive: true,
keywords: ['keyword'],
isTemplate: false,
lastPublishedAt: '2021-03-05T04:32:23Z',
lastChangedAt: null,
...data,
},
],
},
},
});

export const getActiveFlow = getFlowDetails();
export const getInactiveFlow = getFlowDetails(false);
export const getFlowWithoutKeyword = getFlowDetails(true, []);
export const getTemplateFlow = getFlowDetails(true, [], true);
export const getActiveFlow = getFlowDetails({ keywords: ['help'] });
export const getInactiveFlow = getFlowDetails({ isActive: false });
export const getFlowWithoutKeyword = getFlowDetails({ isActive: true, keywords: [] });
export const getTemplateFlow = getFlowDetails({ isActive: true, keywords: [], isTemplate: true });
export const unsavedFlow = getFlowDetails(
{ lastChangedAt: '2021-04-05T04:32:23Z' },
'63397051-789d-418d-9388-2ef7eb1268bb'
);

export const getFlowCountQuery = (filter: any) => ({
request: {
Expand Down
Loading