From 149bfdba4a53baf4cdce78bb50cfa19b1c753d0b Mon Sep 17 00:00:00 2001 From: David Newell Date: Mon, 3 Jul 2023 17:52:46 +0100 Subject: [PATCH] Add snapshot test for atomic saving of notebooks --- frontend/src/initKea.ts | 2 +- .../scenes/notebooks/Notebook/Notebook.tsx | 12 +- .../notebooks/Notebook/notebookLogic.ts | 53 +- .../src/scenes/notebooks/NotebookScene.tsx | 4 +- posthog/api/notebook.py | 2 +- .../__snapshots__/test_notebook.ambr | 709 ++++++++++++++++++ posthog/api/test/notebooks/test_notebook.py | 5 +- 7 files changed, 751 insertions(+), 36 deletions(-) create mode 100644 posthog/api/test/notebooks/__snapshots__/test_notebook.ambr diff --git a/frontend/src/initKea.ts b/frontend/src/initKea.ts index c71326cf32d15..384ae96d60010 100644 --- a/frontend/src/initKea.ts +++ b/frontend/src/initKea.ts @@ -79,7 +79,7 @@ export function initKea({ routerHistory, routerLocation, beforePlugins }: InitKe if ( !ERROR_FILTER_WHITELIST.includes(actionKey) && (error?.message === 'Failed to fetch' || // Likely CORS headers errors (i.e. request failing without reaching Django) - (error?.status !== undefined && ![200, 201, 204, 409].includes(error.status))) + (error?.status !== undefined && ![200, 201, 204].includes(error.status))) ) { lemonToast.error( `${identifierToHuman(actionKey)} failed: ${ diff --git a/frontend/src/scenes/notebooks/Notebook/Notebook.tsx b/frontend/src/scenes/notebooks/Notebook/Notebook.tsx index e07d1a464ea63..2acec2ac692cc 100644 --- a/frontend/src/scenes/notebooks/Notebook/Notebook.tsx +++ b/frontend/src/scenes/notebooks/Notebook/Notebook.tsx @@ -170,7 +170,9 @@ export function Notebook({ shortId, editable = false }: NotebookProps): JSX.Elem
- {!notebook && notebookLoading ? ( + {conflictWarningVisible ? ( + + ) : !notebook && notebookLoading ? (
@@ -178,7 +180,7 @@ export function Notebook({ shortId, editable = false }: NotebookProps): JSX.Elem
) : !notebook ? ( - + ) : isEmpty && !editable ? (

@@ -212,11 +214,7 @@ export function Notebook({ shortId, editable = false }: NotebookProps): JSX.Elem browser. It's a great place to gather ideas before turning into a saved Notebook! ) : null} - {conflictWarningVisible ? ( - - ) : ( - - )} + )}

diff --git a/frontend/src/scenes/notebooks/Notebook/notebookLogic.ts b/frontend/src/scenes/notebooks/Notebook/notebookLogic.ts index 9f82f0edb918f..2d4a66fb339a8 100644 --- a/frontend/src/scenes/notebooks/Notebook/notebookLogic.ts +++ b/frontend/src/scenes/notebooks/Notebook/notebookLogic.ts @@ -61,17 +61,17 @@ export const notebookLogic = kea([ false, { showConflictWarning: () => true, - loadNotebook: () => false, + loadNotebookSuccess: () => false, }, ], }), loaders(({ values, props, actions }) => ({ notebook: [ - undefined as NotebookType | undefined, + null as NotebookType | null, { loadNotebook: async () => { // NOTE: This is all hacky and temporary until we have a backend - let response: NotebookType | undefined + let response: NotebookType | null if (props.shortId === SCRATCHPAD_NOTEBOOK.short_id) { response = { @@ -80,7 +80,8 @@ export const notebookLogic = kea([ version: 0, } } else if (props.shortId.startsWith('template-')) { - response = values.notebookTemplates.find((template) => template.short_id === props.shortId) + response = + values.notebookTemplates.find((template) => template.short_id === props.shortId) || null } else { response = await api.notebooks.get(props.shortId) } @@ -89,7 +90,10 @@ export const notebookLogic = kea([ throw new Error('Notebook not found') } - values.editor?.commands.setContent(response.content) + if (!values.notebook) { + // If this is the first load we need to override the content fully + values.editor?.commands.setContent(response.content) + } return response }, @@ -99,28 +103,37 @@ export const notebookLogic = kea([ return values.notebook } - const response = await api.notebooks.update(values.notebook.short_id, { - version: values.notebook.version, - content: notebook.content, - title: notebook.title, - }) + try { + const response = await api.notebooks.update(values.notebook.short_id, { + version: values.notebook.version, + content: notebook.content, + title: notebook.title, + }) - // If the object is identical then no edits were made, so we can safely clear the local changes - if (notebook.content === values.localContent) { - actions.clearLocalContent() - } + // If the object is identical then no edits were made, so we can safely clear the local changes + if (notebook.content === values.localContent) { + actions.clearLocalContent() + } - return response + return response + } catch (error: any) { + if (error.code === 'conflict') { + actions.showConflictWarning() + return null + } else { + throw error + } + } }, }, ], newNotebook: [ - undefined as NotebookType | undefined, + null as NotebookType | null, { duplicateNotebook: async () => { if (!values.notebook) { - return + return null } // We use the local content if set otherwise the notebook content. That way it supports templates, scratchpad etc. @@ -230,12 +243,6 @@ export const notebookLogic = kea([ saveNotebookSuccess: sharedListeners.onNotebookChange, loadNotebookSuccess: sharedListeners.onNotebookChange, - saveNotebookFailure: ({ errorObject }) => { - if (errorObject.code === 'conflict') { - actions.showConflictWarning() - } - }, - exportJSON: () => { const file = new File( [JSON.stringify(values.editor?.getJSON())], diff --git a/frontend/src/scenes/notebooks/NotebookScene.tsx b/frontend/src/scenes/notebooks/NotebookScene.tsx index 60026169bfb65..67a69dd57d0c9 100644 --- a/frontend/src/scenes/notebooks/NotebookScene.tsx +++ b/frontend/src/scenes/notebooks/NotebookScene.tsx @@ -31,12 +31,12 @@ export const scene: SceneExport = { export function NotebookScene(): JSX.Element { const { notebookId, mode } = useValues(notebookSceneLogic) const { setNotebookMode } = useActions(notebookSceneLogic) - const { notebook, notebookLoading } = useValues(notebookLogic({ shortId: notebookId })) + const { notebook, notebookLoading, conflictWarningVisible } = useValues(notebookLogic({ shortId: notebookId })) const { exportJSON } = useActions(notebookLogic({ shortId: notebookId })) const { selectNotebook, setNotebookSideBarShown } = useActions(notebookSidebarLogic) const { selectedNotebook, notebookSideBarShown } = useValues(notebookSidebarLogic) - if (!notebook && !notebookLoading) { + if (!notebook && !notebookLoading && !conflictWarningVisible) { return } diff --git a/posthog/api/notebook.py b/posthog/api/notebook.py index ae4a0f05160f6..0c063759d43b2 100644 --- a/posthog/api/notebook.py +++ b/posthog/api/notebook.py @@ -100,7 +100,7 @@ def update(self, instance: Notebook, validated_data: Dict, **kwargs) -> Notebook before_update = None with transaction.atomic(): - # Lock the database row so we ensure version updates are atomic + # select_for_update locks the database row so we ensure version updates are atomic locked_instance = Notebook.objects.select_for_update().get(pk=instance.pk) if validated_data.keys(): diff --git a/posthog/api/test/notebooks/__snapshots__/test_notebook.ambr b/posthog/api/test/notebooks/__snapshots__/test_notebook.ambr new file mode 100644 index 0000000000000..929634ace0b5b --- /dev/null +++ b/posthog/api/test/notebooks/__snapshots__/test_notebook.ambr @@ -0,0 +1,709 @@ +# name: TestNotebooks.test_updates_notebook + ' + SELECT "posthog_user"."id", + "posthog_user"."password", + "posthog_user"."last_login", + "posthog_user"."first_name", + "posthog_user"."last_name", + "posthog_user"."is_staff", + "posthog_user"."is_active", + "posthog_user"."date_joined", + "posthog_user"."uuid", + "posthog_user"."current_organization_id", + "posthog_user"."current_team_id", + "posthog_user"."email", + "posthog_user"."pending_email", + "posthog_user"."temporary_token", + "posthog_user"."distinct_id", + "posthog_user"."is_email_verified", + "posthog_user"."has_seen_product_intro_for", + "posthog_user"."email_opt_in", + "posthog_user"."partial_notification_settings", + "posthog_user"."anonymize_data", + "posthog_user"."toolbar_mode", + "posthog_user"."events_column_config" + FROM "posthog_user" + WHERE "posthog_user"."id" = 2 + LIMIT 21 /**/ + ' +--- +# name: TestNotebooks.test_updates_notebook.1 + ' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 /*controller='project_notebooks-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/%3F%24'*/ + ' +--- +# name: TestNotebooks.test_updates_notebook.10 + ' + SELECT "posthog_notebook"."id", + "posthog_notebook"."short_id", + "posthog_notebook"."team_id", + "posthog_notebook"."title", + "posthog_notebook"."content", + "posthog_notebook"."deleted", + "posthog_notebook"."version", + "posthog_notebook"."created_at", + "posthog_notebook"."created_by_id", + "posthog_notebook"."last_modified_at", + "posthog_notebook"."last_modified_by_id" + FROM "posthog_notebook" + WHERE "posthog_notebook"."id" = '01891c84-73f6-0000-8ea4-5d223f446585'::uuid + LIMIT 21 /*controller='project_notebooks-detail',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/%28%3FP%3Cshort_id%3E%5B%5E/.%5D%2B%29/%3F%24'*/ + ' +--- +# name: TestNotebooks.test_updates_notebook.11 + ' + SELECT "posthog_notebook"."id", + "posthog_notebook"."short_id", + "posthog_notebook"."team_id", + "posthog_notebook"."title", + "posthog_notebook"."content", + "posthog_notebook"."deleted", + "posthog_notebook"."version", + "posthog_notebook"."created_at", + "posthog_notebook"."created_by_id", + "posthog_notebook"."last_modified_at", + "posthog_notebook"."last_modified_by_id" + FROM "posthog_notebook" + WHERE "posthog_notebook"."id" = '01891c84-73f6-0000-8ea4-5d223f446585'::uuid + LIMIT 21 + FOR + UPDATE /*controller='project_notebooks-detail',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/%28%3FP%3Cshort_id%3E%5B%5E/.%5D%2B%29/%3F%24'*/ + ' +--- +# name: TestNotebooks.test_updates_notebook.12 + ' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."plugins_opt_in", + "posthog_team"."opt_out_capture", + "posthog_team"."event_names", + "posthog_team"."event_names_with_usage", + "posthog_team"."event_properties", + "posthog_team"."event_properties_with_usage", + "posthog_team"."event_properties_numerical" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 /*controller='project_notebooks-detail',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/%28%3FP%3Cshort_id%3E%5B%5E/.%5D%2B%29/%3F%24'*/ + ' +--- +# name: TestNotebooks.test_updates_notebook.13 + ' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."plugins_opt_in", + "posthog_team"."opt_out_capture", + "posthog_team"."event_names", + "posthog_team"."event_names_with_usage", + "posthog_team"."event_properties", + "posthog_team"."event_properties_with_usage", + "posthog_team"."event_properties_numerical" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 /*controller='project_notebooks-detail',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/%28%3FP%3Cshort_id%3E%5B%5E/.%5D%2B%29/%3F%24'*/ + ' +--- +# name: TestNotebooks.test_updates_notebook.14 + ' + SELECT "posthog_user"."id", + "posthog_user"."password", + "posthog_user"."last_login", + "posthog_user"."first_name", + "posthog_user"."last_name", + "posthog_user"."is_staff", + "posthog_user"."is_active", + "posthog_user"."date_joined", + "posthog_user"."uuid", + "posthog_user"."current_organization_id", + "posthog_user"."current_team_id", + "posthog_user"."email", + "posthog_user"."pending_email", + "posthog_user"."temporary_token", + "posthog_user"."distinct_id", + "posthog_user"."is_email_verified", + "posthog_user"."requested_password_reset_at", + "posthog_user"."has_seen_product_intro_for", + "posthog_user"."email_opt_in", + "posthog_user"."partial_notification_settings", + "posthog_user"."anonymize_data", + "posthog_user"."toolbar_mode", + "posthog_user"."events_column_config" + FROM "posthog_user" + WHERE "posthog_user"."id" = 2 + LIMIT 21 /*controller='project_notebooks-detail',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/%28%3FP%3Cshort_id%3E%5B%5E/.%5D%2B%29/%3F%24'*/ + ' +--- +# name: TestNotebooks.test_updates_notebook.15 + ' + SELECT "posthog_user"."id", + "posthog_user"."password", + "posthog_user"."last_login", + "posthog_user"."first_name", + "posthog_user"."last_name", + "posthog_user"."is_staff", + "posthog_user"."is_active", + "posthog_user"."date_joined", + "posthog_user"."uuid", + "posthog_user"."current_organization_id", + "posthog_user"."current_team_id", + "posthog_user"."email", + "posthog_user"."pending_email", + "posthog_user"."temporary_token", + "posthog_user"."distinct_id", + "posthog_user"."is_email_verified", + "posthog_user"."has_seen_product_intro_for", + "posthog_user"."email_opt_in", + "posthog_user"."partial_notification_settings", + "posthog_user"."anonymize_data", + "posthog_user"."toolbar_mode", + "posthog_user"."events_column_config" + FROM "posthog_user" + WHERE "posthog_user"."id" = 2 + LIMIT 21 /**/ + ' +--- +# name: TestNotebooks.test_updates_notebook.16 + ' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 /*controller='project_notebooks-all-activity',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/activity/%3F%24'*/ + ' +--- +# name: TestNotebooks.test_updates_notebook.17 + ' + SELECT "posthog_organizationmembership"."id", + "posthog_organizationmembership"."organization_id", + "posthog_organizationmembership"."user_id", + "posthog_organizationmembership"."level", + "posthog_organizationmembership"."joined_at", + "posthog_organizationmembership"."updated_at", + "posthog_organization"."id", + "posthog_organization"."name", + "posthog_organization"."slug", + "posthog_organization"."created_at", + "posthog_organization"."updated_at", + "posthog_organization"."plugins_access_level", + "posthog_organization"."for_internal_metrics", + "posthog_organization"."is_member_join_email_enabled", + "posthog_organization"."enforce_2fa", + "posthog_organization"."customer_id", + "posthog_organization"."available_features", + "posthog_organization"."available_product_features", + "posthog_organization"."usage", + "posthog_organization"."setup_section_2_completed", + "posthog_organization"."personalization", + "posthog_organization"."domain_whitelist" + FROM "posthog_organizationmembership" + INNER JOIN "posthog_organization" ON ("posthog_organizationmembership"."organization_id" = "posthog_organization"."id") + WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_notebooks-all-activity',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/activity/%3F%24'*/ + ' +--- +# name: TestNotebooks.test_updates_notebook.18 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:RATE_LIMIT_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_notebooks-all-activity',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/activity/%3F%24'*/ + ' +--- +# name: TestNotebooks.test_updates_notebook.19 + ' + SELECT COUNT(*) AS "__count" + FROM "posthog_activitylog" + WHERE ("posthog_activitylog"."scope" = 'Notebook' + AND "posthog_activitylog"."team_id" = 2) /*controller='project_notebooks-all-activity',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/activity/%3F%24'*/ + ' +--- +# name: TestNotebooks.test_updates_notebook.2 + ' + SELECT "posthog_organizationmembership"."id", + "posthog_organizationmembership"."organization_id", + "posthog_organizationmembership"."user_id", + "posthog_organizationmembership"."level", + "posthog_organizationmembership"."joined_at", + "posthog_organizationmembership"."updated_at", + "posthog_organization"."id", + "posthog_organization"."name", + "posthog_organization"."slug", + "posthog_organization"."created_at", + "posthog_organization"."updated_at", + "posthog_organization"."plugins_access_level", + "posthog_organization"."for_internal_metrics", + "posthog_organization"."is_member_join_email_enabled", + "posthog_organization"."enforce_2fa", + "posthog_organization"."customer_id", + "posthog_organization"."available_features", + "posthog_organization"."available_product_features", + "posthog_organization"."usage", + "posthog_organization"."setup_section_2_completed", + "posthog_organization"."personalization", + "posthog_organization"."domain_whitelist" + FROM "posthog_organizationmembership" + INNER JOIN "posthog_organization" ON ("posthog_organizationmembership"."organization_id" = "posthog_organization"."id") + WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_notebooks-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/%3F%24'*/ + ' +--- +# name: TestNotebooks.test_updates_notebook.20 + ' + SELECT "posthog_activitylog"."id", + "posthog_activitylog"."team_id", + "posthog_activitylog"."organization_id", + "posthog_activitylog"."user_id", + "posthog_activitylog"."is_system", + "posthog_activitylog"."activity", + "posthog_activitylog"."item_id", + "posthog_activitylog"."scope", + "posthog_activitylog"."detail", + "posthog_activitylog"."created_at", + "posthog_user"."id", + "posthog_user"."password", + "posthog_user"."last_login", + "posthog_user"."first_name", + "posthog_user"."last_name", + "posthog_user"."is_staff", + "posthog_user"."is_active", + "posthog_user"."date_joined", + "posthog_user"."uuid", + "posthog_user"."current_organization_id", + "posthog_user"."current_team_id", + "posthog_user"."email", + "posthog_user"."pending_email", + "posthog_user"."temporary_token", + "posthog_user"."distinct_id", + "posthog_user"."is_email_verified", + "posthog_user"."requested_password_reset_at", + "posthog_user"."has_seen_product_intro_for", + "posthog_user"."email_opt_in", + "posthog_user"."partial_notification_settings", + "posthog_user"."anonymize_data", + "posthog_user"."toolbar_mode", + "posthog_user"."events_column_config" + FROM "posthog_activitylog" + LEFT OUTER JOIN "posthog_user" ON ("posthog_activitylog"."user_id" = "posthog_user"."id") + WHERE ("posthog_activitylog"."scope" = 'Notebook' + AND "posthog_activitylog"."team_id" = 2) + ORDER BY "posthog_activitylog"."created_at" DESC + LIMIT 2 /*controller='project_notebooks-all-activity',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/activity/%3F%24'*/ + ' +--- +# name: TestNotebooks.test_updates_notebook.3 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:RATE_LIMIT_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_notebooks-list',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/%3F%24'*/ + ' +--- +# name: TestNotebooks.test_updates_notebook.4 + ' + SELECT "posthog_user"."id", + "posthog_user"."password", + "posthog_user"."last_login", + "posthog_user"."first_name", + "posthog_user"."last_name", + "posthog_user"."is_staff", + "posthog_user"."is_active", + "posthog_user"."date_joined", + "posthog_user"."uuid", + "posthog_user"."current_organization_id", + "posthog_user"."current_team_id", + "posthog_user"."email", + "posthog_user"."pending_email", + "posthog_user"."temporary_token", + "posthog_user"."distinct_id", + "posthog_user"."is_email_verified", + "posthog_user"."has_seen_product_intro_for", + "posthog_user"."email_opt_in", + "posthog_user"."partial_notification_settings", + "posthog_user"."anonymize_data", + "posthog_user"."toolbar_mode", + "posthog_user"."events_column_config" + FROM "posthog_user" + WHERE "posthog_user"."id" = 2 + LIMIT 21 /**/ + ' +--- +# name: TestNotebooks.test_updates_notebook.5 + ' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 /*controller='project_notebooks-detail',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/%28%3FP%3Cshort_id%3E%5B%5E/.%5D%2B%29/%3F%24'*/ + ' +--- +# name: TestNotebooks.test_updates_notebook.6 + ' + SELECT "posthog_organizationmembership"."id", + "posthog_organizationmembership"."organization_id", + "posthog_organizationmembership"."user_id", + "posthog_organizationmembership"."level", + "posthog_organizationmembership"."joined_at", + "posthog_organizationmembership"."updated_at", + "posthog_organization"."id", + "posthog_organization"."name", + "posthog_organization"."slug", + "posthog_organization"."created_at", + "posthog_organization"."updated_at", + "posthog_organization"."plugins_access_level", + "posthog_organization"."for_internal_metrics", + "posthog_organization"."is_member_join_email_enabled", + "posthog_organization"."enforce_2fa", + "posthog_organization"."customer_id", + "posthog_organization"."available_features", + "posthog_organization"."available_product_features", + "posthog_organization"."usage", + "posthog_organization"."setup_section_2_completed", + "posthog_organization"."personalization", + "posthog_organization"."domain_whitelist" + FROM "posthog_organizationmembership" + INNER JOIN "posthog_organization" ON ("posthog_organizationmembership"."organization_id" = "posthog_organization"."id") + WHERE "posthog_organizationmembership"."user_id" = 2 /*controller='project_notebooks-detail',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/%28%3FP%3Cshort_id%3E%5B%5E/.%5D%2B%29/%3F%24'*/ + ' +--- +# name: TestNotebooks.test_updates_notebook.7 + ' + SELECT "posthog_instancesetting"."id", + "posthog_instancesetting"."key", + "posthog_instancesetting"."raw_value" + FROM "posthog_instancesetting" + WHERE "posthog_instancesetting"."key" = 'constance:posthog:RATE_LIMIT_ENABLED' + ORDER BY "posthog_instancesetting"."id" ASC + LIMIT 1 /*controller='project_notebooks-detail',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/%28%3FP%3Cshort_id%3E%5B%5E/.%5D%2B%29/%3F%24'*/ + ' +--- +# name: TestNotebooks.test_updates_notebook.8 + ' + SELECT "posthog_notebook"."id", + "posthog_notebook"."short_id", + "posthog_notebook"."team_id", + "posthog_notebook"."title", + "posthog_notebook"."content", + "posthog_notebook"."deleted", + "posthog_notebook"."version", + "posthog_notebook"."created_at", + "posthog_notebook"."created_by_id", + "posthog_notebook"."last_modified_at", + "posthog_notebook"."last_modified_by_id", + "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."plugins_opt_in", + "posthog_team"."opt_out_capture", + "posthog_team"."event_names", + "posthog_team"."event_names_with_usage", + "posthog_team"."event_properties", + "posthog_team"."event_properties_with_usage", + "posthog_team"."event_properties_numerical", + "posthog_user"."id", + "posthog_user"."password", + "posthog_user"."last_login", + "posthog_user"."first_name", + "posthog_user"."last_name", + "posthog_user"."is_staff", + "posthog_user"."is_active", + "posthog_user"."date_joined", + "posthog_user"."uuid", + "posthog_user"."current_organization_id", + "posthog_user"."current_team_id", + "posthog_user"."email", + "posthog_user"."pending_email", + "posthog_user"."temporary_token", + "posthog_user"."distinct_id", + "posthog_user"."is_email_verified", + "posthog_user"."requested_password_reset_at", + "posthog_user"."has_seen_product_intro_for", + "posthog_user"."email_opt_in", + "posthog_user"."partial_notification_settings", + "posthog_user"."anonymize_data", + "posthog_user"."toolbar_mode", + "posthog_user"."events_column_config", + T4."id", + T4."password", + T4."last_login", + T4."first_name", + T4."last_name", + T4."is_staff", + T4."is_active", + T4."date_joined", + T4."uuid", + T4."current_organization_id", + T4."current_team_id", + T4."email", + T4."pending_email", + T4."temporary_token", + T4."distinct_id", + T4."is_email_verified", + T4."requested_password_reset_at", + T4."has_seen_product_intro_for", + T4."email_opt_in", + T4."partial_notification_settings", + T4."anonymize_data", + T4."toolbar_mode", + T4."events_column_config" + FROM "posthog_notebook" + INNER JOIN "posthog_team" ON ("posthog_notebook"."team_id" = "posthog_team"."id") + LEFT OUTER JOIN "posthog_user" ON ("posthog_notebook"."created_by_id" = "posthog_user"."id") + LEFT OUTER JOIN "posthog_user" T4 ON ("posthog_notebook"."last_modified_by_id" = T4."id") + WHERE ("posthog_notebook"."team_id" = 2 + AND "posthog_notebook"."short_id" = 'uQQDQ33m') + LIMIT 21 /*controller='project_notebooks-detail',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/%28%3FP%3Cshort_id%3E%5B%5E/.%5D%2B%29/%3F%24'*/ + ' +--- +# name: TestNotebooks.test_updates_notebook.9 + ' + SELECT "posthog_team"."id", + "posthog_team"."uuid", + "posthog_team"."organization_id", + "posthog_team"."api_token", + "posthog_team"."app_urls", + "posthog_team"."name", + "posthog_team"."slack_incoming_webhook", + "posthog_team"."created_at", + "posthog_team"."updated_at", + "posthog_team"."anonymize_ips", + "posthog_team"."completed_snippet_onboarding", + "posthog_team"."ingested_event", + "posthog_team"."autocapture_opt_out", + "posthog_team"."autocapture_exceptions_opt_in", + "posthog_team"."autocapture_exceptions_errors_to_ignore", + "posthog_team"."session_recording_opt_in", + "posthog_team"."capture_console_log_opt_in", + "posthog_team"."capture_performance_opt_in", + "posthog_team"."session_recording_version", + "posthog_team"."signup_token", + "posthog_team"."is_demo", + "posthog_team"."access_control", + "posthog_team"."inject_web_apps", + "posthog_team"."test_account_filters", + "posthog_team"."test_account_filters_default_checked", + "posthog_team"."path_cleaning_filters", + "posthog_team"."timezone", + "posthog_team"."data_attributes", + "posthog_team"."person_display_name_properties", + "posthog_team"."live_events_columns", + "posthog_team"."recording_domains", + "posthog_team"."primary_dashboard_id", + "posthog_team"."extra_settings", + "posthog_team"."correlation_config", + "posthog_team"."session_recording_retention_period_days", + "posthog_team"."plugins_opt_in", + "posthog_team"."opt_out_capture", + "posthog_team"."event_names", + "posthog_team"."event_names_with_usage", + "posthog_team"."event_properties", + "posthog_team"."event_properties_with_usage", + "posthog_team"."event_properties_numerical" + FROM "posthog_team" + WHERE "posthog_team"."id" = 2 + LIMIT 21 /*controller='project_notebooks-detail',route='api/projects/%28%3FP%3Cparent_lookup_team_id%3E%5B%5E/.%5D%2B%29/notebooks/%28%3FP%3Cshort_id%3E%5B%5E/.%5D%2B%29/%3F%24'*/ + ' +--- diff --git a/posthog/api/test/notebooks/test_notebook.py b/posthog/api/test/notebooks/test_notebook.py index 0b72e0fb8daa0..bdac77898997e 100644 --- a/posthog/api/test/notebooks/test_notebook.py +++ b/posthog/api/test/notebooks/test_notebook.py @@ -8,10 +8,10 @@ from posthog.models import Team, Organization from posthog.models.notebook.notebook import Notebook from posthog.models.user import User -from posthog.test.base import APIBaseTest +from posthog.test.base import APIBaseTest, QueryMatchingTest, snapshot_postgres_queries -class TestNotebooks(APIBaseTest): +class TestNotebooks(APIBaseTest, QueryMatchingTest): def created_activity(self, item_id: str, short_id: str) -> Dict: return { "activity": "created", @@ -100,6 +100,7 @@ def test_gets_individual_notebook_by_shortid(self) -> None: assert response.status_code == status.HTTP_200_OK assert response.json()["short_id"] == create_response.json()["short_id"] + @snapshot_postgres_queries def test_updates_notebook(self) -> None: response = self.client.post(f"/api/projects/{self.team.id}/notebooks/", data={}) assert response.status_code == status.HTTP_201_CREATED