@oneuptime/common 12.0.14 → 12.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/GlobalOidc.ts +20 -0
- package/Models/DatabaseModels/GlobalSso.ts +20 -0
- package/Models/DatabaseModels/MarketingConversion.ts +19 -9
- package/Models/DatabaseModels/NetworkDeviceLinkRule.ts +46 -0
- package/Models/DatabaseModels/StatusPage.ts +7 -4
- package/Server/API/StatusPageAPI.ts +29 -4
- package/Server/EnvironmentConfig.ts +7 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787800000000-AddScopeToNetworkDeviceLinkRule.ts +19 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787900000000-AddRestrictToAttachedProjectsToGlobalSso.ts +40 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Middleware/SlackAuthorization.ts +43 -6
- package/Server/Middleware/UserAuthorization.ts +236 -26
- package/Server/Middleware/WhatsAppAuthorization.ts +43 -3
- package/Server/Services/GlobalOidcProjectService.ts +126 -1
- package/Server/Services/GlobalOidcService.ts +132 -0
- package/Server/Services/GlobalSsoProjectService.ts +126 -1
- package/Server/Services/GlobalSsoService.ts +132 -0
- package/Server/Services/UserEmailService.ts +4 -4
- package/Server/Utils/CronTab.ts +73 -0
- package/Server/Utils/GlobalSsoAuthorization.ts +175 -0
- package/Server/Utils/Marketing/ConversionUploadProvider.ts +35 -5
- package/Server/Utils/Marketing/Providers/GoogleAds.ts +1 -1
- package/Server/Utils/Marketing/Providers/LinkedIn.ts +1 -1
- package/Server/Utils/Marketing/Providers/Meta.ts +1 -1
- package/Server/Utils/Marketing/Providers/MicrosoftAds.ts +1 -1
- package/Server/Utils/Marketing/Providers/Reddit.ts +1 -1
- package/Server/Utils/Monitor/Criteria/APIRequestCriteria.ts +48 -33
- package/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.ts +35 -30
- package/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.ts +33 -28
- package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +475 -47
- package/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.ts +35 -30
- package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +34 -28
- package/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.ts +33 -28
- package/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.ts +69 -40
- package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +35 -29
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +8 -0
- package/Server/Utils/Monitor/MonitorResource.ts +161 -21
- package/Server/Utils/StatusPageContentSecurityPolicy.ts +56 -0
- package/Server/Utils/StatusPageCustomizationAccess.ts +117 -0
- package/Tests/Server/API/StatusPageCustomizationOrigin.test.ts +348 -0
- package/Tests/Server/Infrastructure/Postgres/FixTotpOtpUrlAlgorithmMigration.test.ts +9 -59
- package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +227 -0
- package/Tests/Server/Middleware/SlackAuthorization.test.ts +149 -0
- package/Tests/Server/Middleware/UserAuthorization.test.ts +27 -13
- package/Tests/Server/Middleware/UserAuthorizationGlobalSsoGovernance.test.ts +1455 -0
- package/Tests/Server/Middleware/UserAuthorizationSSOProvider.test.ts +91 -2
- package/Tests/Server/Middleware/WhatsAppAuthorization.test.ts +233 -0
- package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +21 -8
- package/Tests/Server/Services/GlobalSsoProviderAuthorization.test.ts +1242 -0
- package/Tests/Server/Services/MonitorResourceProbeAgreementHydration.test.ts +459 -0
- package/Tests/Server/Services/MonitorResourceProbeAgreementReuse.test.ts +10 -0
- package/Tests/Server/Types/AnalyticsDatabase/AggregateUtilBucketTimestamp.test.ts +416 -0
- package/Tests/Server/Types/Database/QueryHelperManyToManyAndEmptyValues.test.ts +551 -0
- package/Tests/Server/Types/Database/SelectUtil.test.ts +348 -0
- package/Tests/Server/Utils/CronTab.test.ts +116 -0
- package/Tests/Server/Utils/GlobalSSOToken.test.ts +581 -0
- package/Tests/Server/Utils/GlobalSsoAuthorization.test.ts +1401 -0
- package/Tests/Server/Utils/Marketing/AdUploadableConversionTypes.test.ts +254 -0
- package/Tests/Server/Utils/Marketing/ConversionUploadProvider.test.ts +1 -1
- package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaEvaluateOverTime.test.ts +508 -0
- package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaPortTimings.test.ts +30 -9
- package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +987 -0
- package/Tests/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.test.ts +916 -0
- package/Tests/Server/Utils/Monitor/Criteria/ProfileMonitorCriteria.test.ts +382 -0
- package/Tests/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.test.ts +1219 -0
- package/Tests/Server/Utils/Monitor/MonitorResourceIngestedStepSelection.test.ts +86 -0
- package/Tests/Server/Utils/StatusPageContentSecurityPolicy.test.ts +136 -0
- package/Tests/Server/Utils/StatusPageCustomizationAccess.test.ts +223 -0
- package/Tests/Types/Monitor/MonitorStepConfigHelpers.test.ts +165 -0
- package/Tests/Types/NetworkDevice/NetworkDeviceLinkRuleScope.test.ts +215 -0
- package/Tests/UI/Components/Forms/FormSubmitAnalytics.test.tsx +206 -0
- package/Tests/UI/Utils/AIChatExport/ConversationMarkdown.test.ts +774 -0
- package/Tests/UI/Utils/AIChatExport/MarkdownBlocks.test.ts +791 -0
- package/Tests/UI/Utils/AIChatExport/MarkdownSafety.test.ts +544 -0
- package/Tests/Utils/Analytics.test.ts +187 -0
- package/Tests/Utils/Monitor/MonitorMetricType.test.ts +80 -0
- package/Tests/Utils/Monitor/NetworkDeviceLinkRuleUtil.test.ts +1291 -0
- package/Tests/Utils/NetworkDiscovery/UnclaimedScanDiagnosis.test.ts +214 -0
- package/Types/Marketing/MarketingConversion.ts +12 -0
- package/Types/Monitor/CriteriaFilter.ts +9 -0
- package/Types/NetworkDevice/NetworkDeviceLinkRuleScope.ts +51 -0
- package/UI/Components/FormModal/BasicFormModal.tsx +12 -0
- package/UI/Components/Forms/BasicForm.tsx +13 -1
- package/UI/Components/Forms/BasicModelForm.tsx +2 -1
- package/UI/Components/Forms/ModelForm.tsx +10 -1
- package/UI/Components/Forms/Utils/FormAnalyticsName.ts +39 -0
- package/UI/Components/ModelFormModal/ModelFormModal.tsx +6 -1
- package/Utils/Analytics.ts +55 -2
- package/Utils/Monitor/MonitorMetricType.ts +40 -0
- package/Utils/Monitor/NetworkDeviceLinkRuleUtil.ts +587 -37
- package/Utils/NetworkDiscovery/UnclaimedScanDiagnosis.ts +115 -0
- package/build/dist/Models/DatabaseModels/GlobalOidc.js +21 -0
- package/build/dist/Models/DatabaseModels/GlobalOidc.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalSso.js +21 -0
- package/build/dist/Models/DatabaseModels/GlobalSso.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MarketingConversion.js +20 -10
- package/build/dist/Models/DatabaseModels/MarketingConversion.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceLinkRule.js +47 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceLinkRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +4 -4
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +25 -4
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +6 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787800000000-AddScopeToNetworkDeviceLinkRule.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787800000000-AddScopeToNetworkDeviceLinkRule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787900000000-AddRestrictToAttachedProjectsToGlobalSso.js +29 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787900000000-AddRestrictToAttachedProjectsToGlobalSso.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/SlackAuthorization.js +28 -4
- package/build/dist/Server/Middleware/SlackAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +197 -22
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Middleware/WhatsAppAuthorization.js +32 -2
- package/build/dist/Server/Middleware/WhatsAppAuthorization.js.map +1 -1
- package/build/dist/Server/Services/GlobalOidcProjectService.js +105 -0
- package/build/dist/Server/Services/GlobalOidcProjectService.js.map +1 -1
- package/build/dist/Server/Services/GlobalOidcService.js +127 -0
- package/build/dist/Server/Services/GlobalOidcService.js.map +1 -1
- package/build/dist/Server/Services/GlobalSsoProjectService.js +105 -0
- package/build/dist/Server/Services/GlobalSsoProjectService.js.map +1 -1
- package/build/dist/Server/Services/GlobalSsoService.js +127 -0
- package/build/dist/Server/Services/GlobalSsoService.js.map +1 -1
- package/build/dist/Server/Services/UserEmailService.js +4 -4
- package/build/dist/Server/Utils/CronTab.js +66 -0
- package/build/dist/Server/Utils/CronTab.js.map +1 -1
- package/build/dist/Server/Utils/GlobalSsoAuthorization.js +112 -0
- package/build/dist/Server/Utils/GlobalSsoAuthorization.js.map +1 -0
- package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js +17 -1
- package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js.map +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js.map +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js.map +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/Meta.js +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/Meta.js.map +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js.map +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/Reddit.js +1 -1
- package/build/dist/Server/Utils/Marketing/Providers/Reddit.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js +37 -35
- package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.js +21 -25
- package/build/dist/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js +20 -22
- package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +370 -42
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.js +21 -25
- package/build/dist/Server/Utils/Monitor/Criteria/ExternalStatusPageMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +21 -25
- package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js +21 -25
- package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.js +64 -52
- package/build/dist/Server/Utils/Monitor/Criteria/ServerMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +25 -29
- package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +8 -0
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +123 -23
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/StatusPageContentSecurityPolicy.js +39 -0
- package/build/dist/Server/Utils/StatusPageContentSecurityPolicy.js.map +1 -0
- package/build/dist/Server/Utils/StatusPageCustomizationAccess.js +85 -0
- package/build/dist/Server/Utils/StatusPageCustomizationAccess.js.map +1 -0
- package/build/dist/Types/Marketing/MarketingConversion.js +10 -0
- package/build/dist/Types/Marketing/MarketingConversion.js.map +1 -1
- package/build/dist/Types/Monitor/CriteriaFilter.js +1 -0
- package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
- package/build/dist/Types/NetworkDevice/NetworkDeviceLinkRuleScope.js +46 -0
- package/build/dist/Types/NetworkDevice/NetworkDeviceLinkRuleScope.js.map +1 -0
- package/build/dist/UI/Components/FormModal/BasicFormModal.js +2 -1
- package/build/dist/UI/Components/FormModal/BasicFormModal.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js +10 -1
- package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicModelForm.js +2 -1
- package/build/dist/UI/Components/Forms/BasicModelForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/ModelForm.js +4 -1
- package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
- package/build/dist/UI/Components/Forms/Utils/FormAnalyticsName.js +33 -0
- package/build/dist/UI/Components/Forms/Utils/FormAnalyticsName.js.map +1 -0
- package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js +2 -1
- package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
- package/build/dist/Utils/Analytics.js +50 -2
- package/build/dist/Utils/Analytics.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js +37 -0
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkDeviceLinkRuleUtil.js +318 -37
- package/build/dist/Utils/Monitor/NetworkDeviceLinkRuleUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/UnclaimedScanDiagnosis.js +87 -0
- package/build/dist/Utils/NetworkDiscovery/UnclaimedScanDiagnosis.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import MarketingConversion from "../../../../Models/DatabaseModels/MarketingConversion";
|
|
2
|
+
import ConversionUploadProvider, {
|
|
3
|
+
ConversionSkip,
|
|
4
|
+
ConversionUploadBatchResult,
|
|
5
|
+
} from "../../../../Server/Utils/Marketing/ConversionUploadProvider";
|
|
6
|
+
import GoogleAdsProvider from "../../../../Server/Utils/Marketing/Providers/GoogleAds";
|
|
7
|
+
import LinkedInProvider from "../../../../Server/Utils/Marketing/Providers/LinkedIn";
|
|
8
|
+
import MetaProvider from "../../../../Server/Utils/Marketing/Providers/Meta";
|
|
9
|
+
import MicrosoftAdsProvider from "../../../../Server/Utils/Marketing/Providers/MicrosoftAds";
|
|
10
|
+
import RedditAdsProvider from "../../../../Server/Utils/Marketing/Providers/Reddit";
|
|
11
|
+
import {
|
|
12
|
+
AdUploadableMarketingConversionTypes,
|
|
13
|
+
MarketingConversionType,
|
|
14
|
+
} from "../../../../Types/Marketing/MarketingConversion";
|
|
15
|
+
import { beforeEach, describe, expect, jest, test } from "@jest/globals";
|
|
16
|
+
import { SpyInstance } from "jest-mock";
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
* ---------------------------------------------------------------------------
|
|
20
|
+
* Which conversion types may be uploaded to an ad platform at all.
|
|
21
|
+
*
|
|
22
|
+
* Every provider chooses its platform conversion action with a two-way branch:
|
|
23
|
+
*
|
|
24
|
+
* this.isSignUp(conversion) ? signUpAction : paidSubscriptionAction
|
|
25
|
+
*
|
|
26
|
+
* There is no third arm. So a conversion type nobody wrote a mapping for --
|
|
27
|
+
* MeetingBooked being the first one -- does not get skipped by that branch, it
|
|
28
|
+
* gets uploaded to Google, Meta, Microsoft, LinkedIn and Reddit as a PURCHASE,
|
|
29
|
+
* carrying whatever revenue the ledger row happens to hold. Every downstream
|
|
30
|
+
* bid model then optimises against a booking that bought nothing.
|
|
31
|
+
*
|
|
32
|
+
* The screen is therefore in the base class, ahead of every provider hook,
|
|
33
|
+
* where no provider and no call site can route around it.
|
|
34
|
+
* ---------------------------------------------------------------------------
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
class TestProvider extends ConversionUploadProvider {
|
|
38
|
+
public override readonly key: string = "test";
|
|
39
|
+
public override readonly displayName: string = "Test Provider";
|
|
40
|
+
public providerSkipCalls: number = 0;
|
|
41
|
+
public providerSkip: ConversionSkip | null = null;
|
|
42
|
+
|
|
43
|
+
public override isConfigured(): boolean {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
protected override getProviderSkipReason(
|
|
48
|
+
_conversion: MarketingConversion,
|
|
49
|
+
): ConversionSkip | null {
|
|
50
|
+
this.providerSkipCalls++;
|
|
51
|
+
return this.providerSkip;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public override async upload(
|
|
55
|
+
_conversions: Array<MarketingConversion>,
|
|
56
|
+
): Promise<ConversionUploadBatchResult> {
|
|
57
|
+
return { permanentFailures: new Map<number, string>() };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type MakeConversionFunction = (
|
|
62
|
+
data?: Partial<MarketingConversion>,
|
|
63
|
+
) => MarketingConversion;
|
|
64
|
+
|
|
65
|
+
const makeConversion: MakeConversionFunction = (
|
|
66
|
+
data: Partial<MarketingConversion> = {},
|
|
67
|
+
): MarketingConversion => {
|
|
68
|
+
return Object.assign(new MarketingConversion(), {
|
|
69
|
+
conversionType: MarketingConversionType.SignUp,
|
|
70
|
+
conversionAt: new Date("2026-08-19T10:00:00.000Z"),
|
|
71
|
+
// One click id per platform, so nothing is skipped for lack of one.
|
|
72
|
+
clickIds: {
|
|
73
|
+
gclid: "google-click",
|
|
74
|
+
fbclid: "meta-click",
|
|
75
|
+
msclkid: "microsoft-click",
|
|
76
|
+
li_fat_id: "linkedin-click",
|
|
77
|
+
rdt_cid: "reddit-click",
|
|
78
|
+
},
|
|
79
|
+
...data,
|
|
80
|
+
});
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
describe("ad-uploadable conversion types", () => {
|
|
84
|
+
describe("the allowlist itself", () => {
|
|
85
|
+
test("covers exactly the types every provider has a mapping for", () => {
|
|
86
|
+
expect(AdUploadableMarketingConversionTypes).toEqual([
|
|
87
|
+
MarketingConversionType.SignUp,
|
|
88
|
+
MarketingConversionType.PaidSubscription,
|
|
89
|
+
]);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
/*
|
|
93
|
+
* This is the assertion that fails when someone adds a conversion type.
|
|
94
|
+
* That failure is the prompt to write the per-provider mapping before
|
|
95
|
+
* adding the type to the allowlist -- not to update this expectation.
|
|
96
|
+
*/
|
|
97
|
+
test("does not silently grow when a conversion type is added", () => {
|
|
98
|
+
const unlisted: Array<string> = Object.values(
|
|
99
|
+
MarketingConversionType,
|
|
100
|
+
).filter((type: string) => {
|
|
101
|
+
return !AdUploadableMarketingConversionTypes.includes(
|
|
102
|
+
type as MarketingConversionType,
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
expect(unlisted).toEqual([MarketingConversionType.MeetingBooked]);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe("the base class screen", () => {
|
|
111
|
+
let provider: TestProvider;
|
|
112
|
+
|
|
113
|
+
beforeEach(() => {
|
|
114
|
+
provider = new TestProvider();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("permanently skips a conversion type with no ad platform mapping", () => {
|
|
118
|
+
const skip: ConversionSkip | null = provider.getSkipReason(
|
|
119
|
+
makeConversion({
|
|
120
|
+
conversionType: MarketingConversionType.MeetingBooked,
|
|
121
|
+
}),
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
expect(skip).toEqual({
|
|
125
|
+
reason:
|
|
126
|
+
"Conversion type MeetingBooked has no ad platform conversion mapping",
|
|
127
|
+
isPermanent: true,
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("never lets the provider see an unmapped conversion type", () => {
|
|
132
|
+
provider.getSkipReason(
|
|
133
|
+
makeConversion({
|
|
134
|
+
conversionType: MarketingConversionType.MeetingBooked,
|
|
135
|
+
}),
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
expect(provider.providerSkipCalls).toBe(0);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test.each([
|
|
142
|
+
["an unknown type", "SomethingElse"],
|
|
143
|
+
["an empty type", ""],
|
|
144
|
+
["a lookalike with different casing", "meetingbooked"],
|
|
145
|
+
["a lookalike with different casing", "signup"],
|
|
146
|
+
])("permanently skips %s", (_label: string, conversionType: string) => {
|
|
147
|
+
const skip: ConversionSkip | null = provider.getSkipReason(
|
|
148
|
+
makeConversion({ conversionType: conversionType }),
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
expect(skip?.isPermanent).toBe(true);
|
|
152
|
+
expect(provider.providerSkipCalls).toBe(0);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("names an absent conversion type as unknown rather than blank", () => {
|
|
156
|
+
const conversion: MarketingConversion = makeConversion();
|
|
157
|
+
delete conversion.conversionType;
|
|
158
|
+
|
|
159
|
+
expect(provider.getSkipReason(conversion)).toEqual({
|
|
160
|
+
reason: "Conversion type unknown has no ad platform conversion mapping",
|
|
161
|
+
isPermanent: true,
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
test.each([
|
|
166
|
+
[MarketingConversionType.SignUp],
|
|
167
|
+
[MarketingConversionType.PaidSubscription],
|
|
168
|
+
])(
|
|
169
|
+
"delegates %s to the provider",
|
|
170
|
+
(conversionType: MarketingConversionType) => {
|
|
171
|
+
expect(
|
|
172
|
+
provider.getSkipReason(
|
|
173
|
+
makeConversion({ conversionType: conversionType }),
|
|
174
|
+
),
|
|
175
|
+
).toBeNull();
|
|
176
|
+
expect(provider.providerSkipCalls).toBe(1);
|
|
177
|
+
},
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
test("returns the provider's own skip verbatim for a mapped type", () => {
|
|
181
|
+
provider.providerSkip = {
|
|
182
|
+
reason: "No Google click id",
|
|
183
|
+
isPermanent: true,
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
expect(provider.getSkipReason(makeConversion())).toEqual({
|
|
187
|
+
reason: "No Google click id",
|
|
188
|
+
isPermanent: true,
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
/*
|
|
194
|
+
* The screen is exercised through the real providers too: the guard living
|
|
195
|
+
* in the base class is only worth anything if no provider has quietly
|
|
196
|
+
* overridden getSkipReason back.
|
|
197
|
+
*/
|
|
198
|
+
describe("every shipped provider", () => {
|
|
199
|
+
const providers: Array<[string, ConversionUploadProvider]> = [
|
|
200
|
+
["Google Ads", new GoogleAdsProvider()],
|
|
201
|
+
["Meta", new MetaProvider()],
|
|
202
|
+
["Microsoft Ads", new MicrosoftAdsProvider()],
|
|
203
|
+
["LinkedIn", new LinkedInProvider()],
|
|
204
|
+
["Reddit Ads", new RedditAdsProvider()],
|
|
205
|
+
];
|
|
206
|
+
|
|
207
|
+
test.each(providers)(
|
|
208
|
+
"%s permanently skips a booked meeting that carries its click id",
|
|
209
|
+
(_name: string, provider: ConversionUploadProvider) => {
|
|
210
|
+
const skip: ConversionSkip | null = provider.getSkipReason(
|
|
211
|
+
makeConversion({
|
|
212
|
+
conversionType: MarketingConversionType.MeetingBooked,
|
|
213
|
+
}),
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
expect(skip).toEqual({
|
|
217
|
+
reason:
|
|
218
|
+
"Conversion type MeetingBooked has no ad platform conversion mapping",
|
|
219
|
+
isPermanent: true,
|
|
220
|
+
});
|
|
221
|
+
},
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
test.each(providers)(
|
|
225
|
+
"%s never uploads a booked meeting as a purchase",
|
|
226
|
+
async (_name: string, provider: ConversionUploadProvider) => {
|
|
227
|
+
const meeting: MarketingConversion = makeConversion({
|
|
228
|
+
conversionType: MarketingConversionType.MeetingBooked,
|
|
229
|
+
conversionValueInUSDCents: 500000,
|
|
230
|
+
});
|
|
231
|
+
const uploadSpy: SpyInstance<
|
|
232
|
+
(
|
|
233
|
+
conversions: Array<MarketingConversion>,
|
|
234
|
+
) => Promise<ConversionUploadBatchResult>
|
|
235
|
+
> = jest.spyOn(provider, "upload");
|
|
236
|
+
uploadSpy.mockResolvedValue({
|
|
237
|
+
permanentFailures: new Map<number, string>(),
|
|
238
|
+
} as never);
|
|
239
|
+
|
|
240
|
+
/*
|
|
241
|
+
* The worker only ever calls upload() for conversions getSkipReason
|
|
242
|
+
* cleared, so a permanent skip is exactly "this never reaches the
|
|
243
|
+
* platform".
|
|
244
|
+
*/
|
|
245
|
+
if (!provider.getSkipReason(meeting)) {
|
|
246
|
+
await provider.upload([meeting]);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
expect(uploadSpy).not.toHaveBeenCalled();
|
|
250
|
+
uploadSpy.mockRestore();
|
|
251
|
+
},
|
|
252
|
+
);
|
|
253
|
+
});
|
|
254
|
+
});
|