@atproto/api 0.20.23 → 0.20.25

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.
Files changed (57) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/package.json +22 -16
  3. package/definitions/labels.json +0 -170
  4. package/docs/moderation.md +0 -260
  5. package/jest.config.cjs +0 -23
  6. package/jest.d.ts +0 -20
  7. package/jest.setup.ts +0 -97
  8. package/scripts/code/labels.mjs +0 -77
  9. package/scripts/generate-code.mjs +0 -4
  10. package/src/age-assurance.test.ts +0 -218
  11. package/src/age-assurance.ts +0 -137
  12. package/src/agent.ts +0 -1645
  13. package/src/atp-agent.ts +0 -570
  14. package/src/bsky-agent.ts +0 -14
  15. package/src/const.ts +0 -1
  16. package/src/index.ts +0 -44
  17. package/src/mocker.ts +0 -220
  18. package/src/moderation/decision.ts +0 -389
  19. package/src/moderation/index.ts +0 -69
  20. package/src/moderation/mutewords.ts +0 -170
  21. package/src/moderation/subjects/account.ts +0 -44
  22. package/src/moderation/subjects/feed-generator.ts +0 -24
  23. package/src/moderation/subjects/notification.ts +0 -25
  24. package/src/moderation/subjects/post.ts +0 -433
  25. package/src/moderation/subjects/profile.ts +0 -26
  26. package/src/moderation/subjects/status.ts +0 -27
  27. package/src/moderation/subjects/user-list.ts +0 -48
  28. package/src/moderation/types.ts +0 -191
  29. package/src/moderation/ui.ts +0 -21
  30. package/src/moderation/util.ts +0 -111
  31. package/src/predicate.ts +0 -52
  32. package/src/rich-text/detection.ts +0 -146
  33. package/src/rich-text/rich-text.ts +0 -418
  34. package/src/rich-text/sanitization.ts +0 -42
  35. package/src/rich-text/unicode.ts +0 -47
  36. package/src/rich-text/util.ts +0 -15
  37. package/src/session-manager.ts +0 -5
  38. package/src/types.ts +0 -165
  39. package/src/util.ts +0 -96
  40. package/tests/atp-agent.test.ts +0 -3863
  41. package/tests/dispatcher.test.ts +0 -527
  42. package/tests/errors.test.ts +0 -29
  43. package/tests/moderation-behaviors.test.ts +0 -951
  44. package/tests/moderation-custom-labels.test.ts +0 -334
  45. package/tests/moderation-mutewords.test.ts +0 -1299
  46. package/tests/moderation-prefs.test.ts +0 -402
  47. package/tests/moderation-quoteposts.test.ts +0 -277
  48. package/tests/moderation.test.ts +0 -739
  49. package/tests/rich-text-detection.test.ts +0 -456
  50. package/tests/rich-text-sanitization.test.ts +0 -216
  51. package/tests/rich-text.test.ts +0 -705
  52. package/tests/util/echo-server.ts +0 -37
  53. package/tests/util/moderation-behavior.ts +0 -268
  54. package/tsconfig.build.json +0 -9
  55. package/tsconfig.build.tsbuildinfo +0 -1
  56. package/tsconfig.json +0 -7
  57. package/tsconfig.tests.json +0 -10
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @atproto/api
2
2
 
3
+ ## 0.20.25
4
+
5
+ ### Patch Changes
6
+
7
+ - [#5179](https://github.com/bluesky-social/atproto/pull/5179) [`f6409db`](https://github.com/bluesky-social/atproto/commit/f6409dbcefdd5565b1ba23c52dc71ec7e791e2e9) Thanks [@estrattonbailey](https://github.com/estrattonbailey)! - Support the new timestamp field, along with transactionId and errorCode, on KWS age verification status payloads. Add additionalVerificationMethods to Age Assurance config.
8
+
9
+ ## 0.20.24
10
+
11
+ ### Patch Changes
12
+
13
+ - [#5099](https://github.com/bluesky-social/atproto/pull/5099) [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Update TypeScript build to rely on references to composite internal projects
14
+
15
+ - [#5099](https://github.com/bluesky-social/atproto/pull/5099) [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Bundle only necessary files in the NPM tarball, including the `CHANGELOG.md` and `README.md` files (if present).
16
+
17
+ - Updated dependencies [[`28a0b58`](https://github.com/bluesky-social/atproto/commit/28a0b588147863eaef948cd2bb8fc0f19d08cda9), [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07), [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07), [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07), [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07)]:
18
+ - @atproto/syntax@0.6.4
19
+ - @atproto/common-web@0.5.3
20
+ - @atproto/lexicon@0.7.4
21
+ - @atproto/xrpc@0.8.3
22
+
3
23
  ## 0.20.23
4
24
 
5
25
  ### Patch Changes
package/package.json CHANGED
@@ -1,9 +1,6 @@
1
1
  {
2
2
  "name": "@atproto/api",
3
- "version": "0.20.23",
4
- "engines": {
5
- "node": ">=22"
6
- },
3
+ "version": "0.20.25",
7
4
  "license": "MIT",
8
5
  "description": "Client library for atproto and Bluesky",
9
6
  "keywords": [
@@ -17,29 +14,38 @@
17
14
  "url": "https://github.com/bluesky-social/atproto",
18
15
  "directory": "packages/api"
19
16
  },
17
+ "files": [
18
+ "./dist",
19
+ "./OAUTH.md",
20
+ "./README.md",
21
+ "./CHANGELOG.md"
22
+ ],
23
+ "type": "module",
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "default": "./dist/index.js"
28
+ }
29
+ },
30
+ "engines": {
31
+ "node": ">=22"
32
+ },
20
33
  "dependencies": {
21
34
  "await-lock": "^3.0.0",
22
35
  "multiformats": "^13.0.0",
23
36
  "tlds": "^1.234.0",
24
37
  "zod": "^3.23.8",
25
- "@atproto/lexicon": "^0.7.3",
26
- "@atproto/common-web": "^0.5.2",
27
- "@atproto/syntax": "^0.6.3",
28
- "@atproto/xrpc": "^0.8.2"
38
+ "@atproto/common-web": "^0.5.3",
39
+ "@atproto/syntax": "^0.6.4",
40
+ "@atproto/xrpc": "^0.8.3",
41
+ "@atproto/lexicon": "^0.7.4"
29
42
  },
30
43
  "devDependencies": {
31
44
  "@jest/globals": "^28.1.3",
32
45
  "http-terminator": "^3.2.0",
33
46
  "jest": "^30.0.0",
34
47
  "prettier": "^3.2.5",
35
- "@atproto/lex-cli": "^0.10.2"
36
- },
37
- "type": "module",
38
- "exports": {
39
- ".": {
40
- "types": "./dist/index.d.ts",
41
- "default": "./dist/index.js"
42
- }
48
+ "@atproto/lex-cli": "^0.10.3"
43
49
  },
44
50
  "scripts": {
45
51
  "codegen:lex": "lex gen-api --yes ./src/client ../../lexicons/com/atproto/*/* ../../lexicons/app/bsky/*/* ../../lexicons/chat/bsky/*/* ../../lexicons/tools/ozone/*/* ../../lexicons/com/germnetwork/*",
@@ -1,170 +0,0 @@
1
- [
2
- {
3
- "identifier": "!hide",
4
- "configurable": false,
5
- "defaultSetting": "hide",
6
- "flags": ["no-override", "no-self"],
7
- "severity": "alert",
8
- "blurs": "content",
9
- "behaviors": {
10
- "account": {
11
- "profileList": "blur",
12
- "profileView": "blur",
13
- "avatar": "blur",
14
- "banner": "blur",
15
- "displayName": "blur",
16
- "contentList": "blur",
17
- "contentView": "blur"
18
- },
19
- "profile": {
20
- "avatar": "blur",
21
- "banner": "blur",
22
- "displayName": "blur"
23
- },
24
- "content": {
25
- "contentList": "blur",
26
- "contentView": "blur"
27
- }
28
- }
29
- },
30
- {
31
- "identifier": "!warn",
32
- "configurable": false,
33
- "defaultSetting": "warn",
34
- "flags": ["no-self"],
35
- "severity": "none",
36
- "blurs": "content",
37
- "behaviors": {
38
- "account": {
39
- "profileList": "blur",
40
- "profileView": "blur",
41
- "avatar": "blur",
42
- "banner": "blur",
43
- "contentList": "blur",
44
- "contentView": "blur"
45
- },
46
- "profile": {
47
- "avatar": "blur",
48
- "banner": "blur",
49
- "displayName": "blur"
50
- },
51
- "content": {
52
- "contentList": "blur",
53
- "contentView": "blur"
54
- }
55
- }
56
- },
57
- {
58
- "identifier": "!no-unauthenticated",
59
- "configurable": false,
60
- "defaultSetting": "hide",
61
- "flags": ["no-override", "unauthed"],
62
- "severity": "none",
63
- "blurs": "content",
64
- "behaviors": {
65
- "account": {
66
- "profileList": "blur",
67
- "profileView": "blur",
68
- "avatar": "blur",
69
- "banner": "blur",
70
- "displayName": "blur",
71
- "contentList": "blur",
72
- "contentView": "blur"
73
- },
74
- "profile": {
75
- "avatar": "blur",
76
- "banner": "blur",
77
- "displayName": "blur"
78
- },
79
- "content": {
80
- "contentList": "blur",
81
- "contentView": "blur"
82
- }
83
- }
84
- },
85
- {
86
- "identifier": "porn",
87
- "configurable": true,
88
- "defaultSetting": "hide",
89
- "flags": ["adult"],
90
- "severity": "none",
91
- "blurs": "media",
92
- "behaviors": {
93
- "account": {
94
- "avatar": "blur",
95
- "banner": "blur"
96
- },
97
- "profile": {
98
- "avatar": "blur",
99
- "banner": "blur"
100
- },
101
- "content": {
102
- "contentMedia": "blur"
103
- }
104
- }
105
- },
106
- {
107
- "identifier": "sexual",
108
- "configurable": true,
109
- "defaultSetting": "warn",
110
- "flags": ["adult"],
111
- "severity": "none",
112
- "blurs": "media",
113
- "behaviors": {
114
- "account": {
115
- "avatar": "blur",
116
- "banner": "blur"
117
- },
118
- "profile": {
119
- "avatar": "blur",
120
- "banner": "blur"
121
- },
122
- "content": {
123
- "contentMedia": "blur"
124
- }
125
- }
126
- },
127
- {
128
- "identifier": "nudity",
129
- "configurable": true,
130
- "defaultSetting": "ignore",
131
- "flags": [],
132
- "severity": "none",
133
- "blurs": "media",
134
- "behaviors": {
135
- "account": {
136
- "avatar": "blur",
137
- "banner": "blur"
138
- },
139
- "profile": {
140
- "avatar": "blur",
141
- "banner": "blur"
142
- },
143
- "content": {
144
- "contentMedia": "blur"
145
- }
146
- }
147
- },
148
- {
149
- "identifier": "graphic-media",
150
- "alias": ["gore"],
151
- "flags": ["adult"],
152
- "configurable": true,
153
- "defaultSetting": "warn",
154
- "severity": "none",
155
- "blurs": "media",
156
- "behaviors": {
157
- "account": {
158
- "avatar": "blur",
159
- "banner": "blur"
160
- },
161
- "profile": {
162
- "avatar": "blur",
163
- "banner": "blur"
164
- },
165
- "content": {
166
- "contentMedia": "blur"
167
- }
168
- }
169
- }
170
- ]
@@ -1,260 +0,0 @@
1
- # Moderation API
2
-
3
- Applying the moderation system is a challenging task, but we've done our best to simplify it for you. The Moderation API helps handle a wide range of tasks, including:
4
-
5
- - Moderator labeling
6
- - User muting (including mutelists)
7
- - User blocking
8
- - Mutewords
9
- - Hidden posts
10
-
11
- ## Configuration
12
-
13
- Every moderation function takes a set of options which look like this:
14
-
15
- ```typescript
16
- {
17
- // the logged-in user's DID
18
- userDid: 'did:plc:1234...',
19
-
20
- moderationPrefs: {
21
- // is adult content allowed?
22
- adultContentEnabled: true,
23
-
24
- // the global label settings (used on self-labels)
25
- labels: {
26
- porn: 'hide',
27
- sexual: 'warn',
28
- nudity: 'ignore',
29
- // ...
30
- },
31
-
32
- // the subscribed labelers and their label settings
33
- labelers: [
34
- {
35
- did: 'did:plc:1234...',
36
- labels: {
37
- porn: 'hide',
38
- sexual: 'warn',
39
- nudity: 'ignore',
40
- // ...
41
- }
42
- }
43
- ],
44
-
45
- mutedWords: [/* ... */],
46
- hiddenPosts: [/* ... */]
47
- },
48
-
49
- // custom label definitions
50
- labelDefs: {
51
- // labelerDid => defs[]
52
- 'did:plc:1234...': [
53
- /* ... */
54
- ]
55
- }
56
- }
57
- ```
58
-
59
- This should match the following interfaces:
60
-
61
- ```typescript
62
- export interface ModerationPrefsLabeler {
63
- did: string
64
- labels: Record<string, LabelPreference>
65
- }
66
-
67
- export interface ModerationPrefs {
68
- adultContentEnabled: boolean
69
- labels: Record<string, LabelPreference>
70
- labelers: ModerationPrefsLabeler[]
71
- mutedWords: AppBskyActorDefs.MutedWord[]
72
- hiddenPosts: string[]
73
- }
74
-
75
- export interface ModerationOpts {
76
- userDid: string | undefined
77
- prefs: ModerationPrefs
78
- /**
79
- * Map of labeler did -> custom definitions
80
- */
81
- labelDefs?: Record<string, InterpretedLabelValueDefinition[]>
82
- }
83
- ```
84
-
85
- You can quickly grab the `ModerationPrefs` using the `agent.getPreferences()` method:
86
-
87
- ```typescript
88
- const prefs = await agent.getPreferences()
89
- moderatePost(post, {
90
- userDid: /*...*/,
91
- prefs: prefs.moderationPrefs,
92
- labelDefs: /*...*/
93
- })
94
- ```
95
-
96
- To gather the label definitions (`labelDefs`) see the _Labelers_ section below.
97
-
98
- ## Labelers
99
-
100
- Labelers are services that provide moderation labels. Your application will typically have 1+ top-level labelers set with the ability to do "takedowns" on content. This is controlled via this static function, though the default is to use Bluesky's moderation:
101
-
102
- ```typescript
103
- BskyAgent.configure({
104
- appLabelers: ['did:web:my-labeler.com'],
105
- })
106
- ```
107
-
108
- Users may also add their own labelers. The active labelers are controlled via an HTTP header which is automatically set by the agent when `getPreferences` is called, or when the labeler preferences are changed.
109
-
110
- Labelers publish a `app.bsky.labeler.service` record that looks like this:
111
-
112
- ```js
113
- {
114
- $type: 'app.bsky.labeler.service',
115
- policies: {
116
- // the list of label values the labeler will publish
117
- labelValues: [
118
- 'rude',
119
- ],
120
- // any custom definitions the labeler will be using
121
- labelValueDefinitions: [
122
- {
123
- identifier: 'rude',
124
- blurs: 'content',
125
- severity: 'alert',
126
- defaultSetting: 'warn',
127
- adultOnly: false,
128
- locales: [
129
- {
130
- lang: 'en',
131
- name: 'Rude',
132
- description: 'Not keeping things civil.',
133
- },
134
- ],
135
- },
136
- ],
137
- },
138
- createdAt: '2024-03-12T17:17:17.215Z'
139
- }
140
- ```
141
-
142
- The label value definition are custom labels which only apply to that labeler. Your client needs to sync those definitions in order to correctly interpret them. To do that, call `app.bsky.labeler.getService()` (or the `getServices` batch variant) periodically to fetch their definitions. We recommend caching the response (at time our writing the official client uses a TTL of 6 hours).
143
-
144
- Here is how to do this:
145
-
146
- ```typescript
147
- import { AtpAgent } from '@atproto/api'
148
-
149
- const agent = new AtpAgent({ service: 'https://example.com' })
150
- // assume `agent` is a signed in session
151
- const prefs = await agent.getPreferences()
152
- const labelDefs = await agent.getLabelDefinitions(prefs)
153
-
154
- moderatePost(post, {
155
- userDid: agent.session.did,
156
- prefs: prefs.moderationPrefs,
157
- labelDefs,
158
- })
159
- ```
160
-
161
- ## The `moderate*()` APIs
162
-
163
- The SDK exports methods to moderate the different kinds of content on the network.
164
-
165
- ```typescript
166
- import {
167
- moderateProfile,
168
- moderatePost,
169
- moderateNotification,
170
- moderateFeedGen,
171
- moderateUserList,
172
- moderateLabeler,
173
- } from '@atproto/api'
174
- ```
175
-
176
- Each of these follows the same API signature:
177
-
178
- ```typescript
179
- const res = moderatePost(post, moderationOptions)
180
- ```
181
-
182
- The response object provides an API for figuring out what your UI should do in different contexts.
183
-
184
- ```typescript
185
- res.ui(context) /* =>
186
-
187
- ModerationUI {
188
- filter: boolean // should the content be removed from the interface?
189
- blur: boolean // should the content be put behind a cover?
190
- alert: boolean // should an alert be put on the content? (negative)
191
- inform: boolean // should an informational notice be put on the content? (neutral)
192
- noOverride: boolean // if blur=true, should the UI disable opening the cover?
193
-
194
- // the reasons for each of the flags:
195
- filters: ModerationCause[]
196
- blurs: ModerationCause[]
197
- alerts: ModerationCause[]
198
- informs: ModerationCause[]
199
- }
200
- */
201
- ```
202
-
203
- There are multiple UI contexts available:
204
-
205
- - `profileList` A profile being listed, eg in search or a follower list
206
- - `profileView` A profile being viewed directly
207
- - `avatar` The user's avatar in any context
208
- - `banner` The user's banner in any context
209
- - `displayName` The user's display name in any context
210
- - `contentList` Content being listed, eg posts in a feed, posts as replies, a user list list, a feed generator list, etc
211
- - `contentView` Content being viewed direct, eg an opened post, the user list page, the feedgen page, etc
212
- - `contentMedia ` Media inside the content, eg a picture embedded in a post
213
-
214
- Here's how a post in a feed would use these tools to make a decision:
215
-
216
- ```typescript
217
- const mod = moderatePost(post, moderationOptions)
218
-
219
- if (mod.ui('contentList').filter) {
220
- // dont show the post
221
- }
222
- if (mod.ui('contentList').blur) {
223
- // cover the post with the explanation from mod.ui('contentList').blurs[0]
224
- if (mod.ui('contentList').noOverride) {
225
- // dont allow the cover to be removed
226
- }
227
- }
228
- if (mod.ui('contentMedia').blur) {
229
- // cover the post's embedded images with the explanation from mod.ui('contentMedia').blurs[0]
230
- if (mod.ui('contentMedia').noOverride) {
231
- // dont allow the cover to be removed
232
- }
233
- }
234
- if (mod.ui('avatar').blur) {
235
- // cover the avatar with the explanation from mod.ui('avatar').blurs[0]
236
- if (mod.ui('avatar').noOverride) {
237
- // dont allow the cover to be removed
238
- }
239
- }
240
- for (const alert of mod.ui('contentList').alerts) {
241
- // render this alert
242
- }
243
- for (const inform of mod.ui('contentList').informs) {
244
- // render this inform
245
- }
246
- ```
247
-
248
- ## Sending moderation reports
249
-
250
- Any Labeler is capable of receiving moderation reports. As a result, you need to specify which labeler should receive the report. You do this with the `Atproto-Proxy` header:
251
-
252
- ```typescript
253
- agent
254
- .withProxy('atproto_labeler', 'did:web:my-labeler.com')
255
- .createModerationReport({
256
- reasonType: 'com.atproto.moderation.defs#reasonViolation',
257
- reason: 'They were being such a jerk to me!',
258
- subject: { did: 'did:web:bob.com' },
259
- })
260
- ```
package/jest.config.cjs DELETED
@@ -1,23 +0,0 @@
1
- /** @type {import('jest').Config} */
2
- module.exports = {
3
- displayName: 'API',
4
- transform: {
5
- '^.+\\.(t|j)s$': [
6
- '@swc/jest',
7
- {
8
- jsc: {
9
- parser: { syntax: 'typescript', importAttributes: true },
10
- experimental: { keepImportAttributes: true },
11
- transform: {},
12
- },
13
- module: { type: 'es6' },
14
- },
15
- ],
16
- },
17
- extensionsToTreatAsEsm: ['.ts'],
18
- transformIgnorePatterns: [],
19
- testTimeout: 60000,
20
- setupFiles: ['<rootDir>/../../test.setup.ts'],
21
- setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
22
- moduleNameMapper: { '^(\\.\\.?\\/.+)\\.js$': ['$1.ts', '$1.js'] },
23
- }
package/jest.d.ts DELETED
@@ -1,20 +0,0 @@
1
- declare namespace jest {
2
- // eslint-disable-next-line
3
- interface Matchers<R, T = {}> {
4
- toBeModerationResult(
5
- expected: ModerationTestSuiteResultFlag[] | undefined,
6
- context?: string,
7
- stringifiedResult?: string,
8
- ignoreCause?: boolean,
9
- ): R
10
- }
11
-
12
- interface Expect {
13
- toBeModerationResult(
14
- expected: ModerationTestSuiteResultFlag[] | undefined,
15
- context?: string,
16
- stringifiedResult?: string,
17
- ignoreCause?: boolean,
18
- ): void
19
- }
20
- }
package/jest.setup.ts DELETED
@@ -1,97 +0,0 @@
1
- import { ModerationUI } from './src/index.js'
2
- import { ModerationTestSuiteResultFlag } from './tests/util/moderation-behavior.js'
3
-
4
- expect.extend({
5
- toBeModerationResult(
6
- actual: ModerationUI,
7
- expected: ModerationTestSuiteResultFlag[] | undefined,
8
- context = '',
9
- stringifiedResult: string | undefined = undefined,
10
- _ignoreCause = false,
11
- ) {
12
- const fail = (msg: string) => ({
13
- pass: false,
14
- message: () =>
15
- `${msg}.${
16
- stringifiedResult ? ` Full result: ${stringifiedResult}` : ''
17
- }`,
18
- })
19
- // let cause = actual.causes?.type as string
20
- // if (actual.cause?.type === 'label') {
21
- // cause = `label:${actual.cause.labelDef.id}`
22
- // } else if (actual.cause?.type === 'muted') {
23
- // if (actual.cause.source.type === 'list') {
24
- // cause = 'muted-by-list'
25
- // }
26
- // } else if (actual.cause?.type === 'blocking') {
27
- // if (actual.cause.source.type === 'list') {
28
- // cause = 'blocking-by-list'
29
- // }
30
- // }
31
- if (!expected) {
32
- // if (!ignoreCause && actual.cause) {
33
- // return fail(`${context} expected to be a no-op, got ${cause}`)
34
- // }
35
- if (actual.inform) {
36
- return fail(`${context} expected to be a no-op, got inform=true`)
37
- }
38
- if (actual.alert) {
39
- return fail(`${context} expected to be a no-op, got alert=true`)
40
- }
41
- if (actual.blur) {
42
- return fail(`${context} expected to be a no-op, got blur=true`)
43
- }
44
- if (actual.filter) {
45
- return fail(`${context} expected to be a no-op, got filter=true`)
46
- }
47
- if (actual.noOverride) {
48
- return fail(`${context} expected to be a no-op, got noOverride=true`)
49
- }
50
- } else {
51
- // if (!ignoreCause && cause !== expected.cause) {
52
- // return fail(`${context} expected to be ${expected.cause}, got ${cause}`)
53
- // }
54
- const expectedInform = expected.includes('inform')
55
- if (!!actual.inform !== expectedInform) {
56
- return fail(
57
- `${context} expected to be inform=${expectedInform}, got ${
58
- actual.inform || false
59
- }`,
60
- )
61
- }
62
- const expectedAlert = expected.includes('alert')
63
- if (!!actual.alert !== expectedAlert) {
64
- return fail(
65
- `${context} expected to be alert=${expectedAlert}, got ${
66
- actual.alert || false
67
- }`,
68
- )
69
- }
70
- const expectedBlur = expected.includes('blur')
71
- if (!!actual.blur !== expectedBlur) {
72
- return fail(
73
- `${context} expected to be blur=${expectedBlur}, got ${
74
- actual.blur || false
75
- }`,
76
- )
77
- }
78
- const expectedFilter = expected.includes('filter')
79
- if (!!actual.filter !== expectedFilter) {
80
- return fail(
81
- `${context} expected to be filter=${expectedFilter}, got ${
82
- actual.filter || false
83
- }`,
84
- )
85
- }
86
- const expectedNoOverride = expected.includes('noOverride')
87
- if (!!actual.noOverride !== expectedNoOverride) {
88
- return fail(
89
- `${context} expected to be noOverride=${expectedNoOverride}, got ${
90
- actual.noOverride || false
91
- }`,
92
- )
93
- }
94
- }
95
- return { pass: true, message: () => '' }
96
- },
97
- })