flash-notifications 0.0.38 → 0.0.40
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/README.md +66 -1
- package/build/container/index.d.ts +12 -0
- package/build/container/index.d.ts.map +1 -1
- package/build/container/index.js +50 -8
- package/build/container/notification.d.ts.map +1 -1
- package/build/container/notification.js +5 -2
- package/build/flash-notifications.d.ts +2 -2
- package/build/flash-notifications.d.ts.map +1 -1
- package/build/flash-notifications.js +11 -4
- package/build/listener.d.ts.map +1 -1
- package/package.json +17 -10
- package/.eslintrc.js +0 -12
- package/AGENTS.md +0 -3
- package/CHANGELOG.md +0 -10
- package/android/build.gradle +0 -43
- package/android/src/main/AndroidManifest.xml +0 -2
- package/android/src/main/java/expo/modules/flashnotifications/FlashNotificationsModule.kt +0 -50
- package/android/src/main/java/expo/modules/flashnotifications/FlashNotificationsView.kt +0 -30
- package/expo-module.config.json +0 -17
- package/ios/FlashNotifications.podspec +0 -29
- package/ios/FlashNotificationsModule.swift +0 -48
- package/ios/FlashNotificationsView.swift +0 -38
- package/peak_flow.yml +0 -5
- package/scripts/velocious-test.js +0 -186
- package/spec/flash-notifications-spec.js +0 -46
- package/spec/support/dummy-http-server.js +0 -52
- package/spec/support/system-test-helper.js +0 -99
- package/src/configuration.js +0 -10
- package/src/container/index.jsx +0 -214
- package/src/container/notification.jsx +0 -130
- package/src/debug.js +0 -13
- package/src/events.js +0 -7
- package/src/flash-notifications.js +0 -99
- package/src/index.js +0 -15
- package/src/listener.js +0 -56
- package/tsconfig.json +0 -15
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
package expo.modules.flashnotifications
|
|
2
|
-
|
|
3
|
-
import expo.modules.kotlin.modules.Module
|
|
4
|
-
import expo.modules.kotlin.modules.ModuleDefinition
|
|
5
|
-
import java.net.URL
|
|
6
|
-
|
|
7
|
-
class FlashNotificationsModule : Module() {
|
|
8
|
-
// Each module class must implement the definition function. The definition consists of components
|
|
9
|
-
// that describes the module's functionality and behavior.
|
|
10
|
-
// See https://docs.expo.dev/modules/module-api for more details about available components.
|
|
11
|
-
override fun definition() = ModuleDefinition {
|
|
12
|
-
// Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument.
|
|
13
|
-
// Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
|
|
14
|
-
// The module will be accessible from `requireNativeModule('FlashNotifications')` in JavaScript.
|
|
15
|
-
Name("FlashNotifications")
|
|
16
|
-
|
|
17
|
-
// Sets constant properties on the module. Can take a dictionary or a closure that returns a dictionary.
|
|
18
|
-
Constants(
|
|
19
|
-
"PI" to Math.PI
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
// Defines event names that the module can send to JavaScript.
|
|
23
|
-
Events("onChange")
|
|
24
|
-
|
|
25
|
-
// Defines a JavaScript synchronous function that runs the native code on the JavaScript thread.
|
|
26
|
-
Function("hello") {
|
|
27
|
-
"Hello world! 👋"
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Defines a JavaScript function that always returns a Promise and whose native code
|
|
31
|
-
// is by default dispatched on the different thread than the JavaScript runtime runs on.
|
|
32
|
-
AsyncFunction("setValueAsync") { value: String ->
|
|
33
|
-
// Send an event to JavaScript.
|
|
34
|
-
sendEvent("onChange", mapOf(
|
|
35
|
-
"value" to value
|
|
36
|
-
))
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Enables the module to be used as a native view. Definition components that are accepted as part of
|
|
40
|
-
// the view definition: Prop, Events.
|
|
41
|
-
View(FlashNotificationsView::class) {
|
|
42
|
-
// Defines a setter for the `url` prop.
|
|
43
|
-
Prop("url") { view: FlashNotificationsView, url: URL ->
|
|
44
|
-
view.webView.loadUrl(url.toString())
|
|
45
|
-
}
|
|
46
|
-
// Defines an event that the view can send to JavaScript.
|
|
47
|
-
Events("onLoad")
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
package expo.modules.flashnotifications
|
|
2
|
-
|
|
3
|
-
import android.content.Context
|
|
4
|
-
import android.webkit.WebView
|
|
5
|
-
import android.webkit.WebViewClient
|
|
6
|
-
import expo.modules.kotlin.AppContext
|
|
7
|
-
import expo.modules.kotlin.viewevent.EventDispatcher
|
|
8
|
-
import expo.modules.kotlin.views.ExpoView
|
|
9
|
-
|
|
10
|
-
class FlashNotificationsView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
|
|
11
|
-
// Creates and initializes an event dispatcher for the `onLoad` event.
|
|
12
|
-
// The name of the event is inferred from the value and needs to match the event name defined in the module.
|
|
13
|
-
private val onLoad by EventDispatcher()
|
|
14
|
-
|
|
15
|
-
// Defines a WebView that will be used as the root subview.
|
|
16
|
-
internal val webView = WebView(context).apply {
|
|
17
|
-
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
|
18
|
-
webViewClient = object : WebViewClient() {
|
|
19
|
-
override fun onPageFinished(view: WebView, url: String) {
|
|
20
|
-
// Sends an event to JavaScript. Triggers a callback defined on the view component in JavaScript.
|
|
21
|
-
onLoad(mapOf("url" to url))
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
init {
|
|
27
|
-
// Adds the WebView to the view hierarchy.
|
|
28
|
-
addView(webView)
|
|
29
|
-
}
|
|
30
|
-
}
|
package/expo-module.config.json
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
require 'json'
|
|
2
|
-
|
|
3
|
-
package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
|
|
4
|
-
|
|
5
|
-
Pod::Spec.new do |s|
|
|
6
|
-
s.name = 'FlashNotifications'
|
|
7
|
-
s.version = package['version']
|
|
8
|
-
s.summary = package['description']
|
|
9
|
-
s.description = package['description']
|
|
10
|
-
s.license = package['license']
|
|
11
|
-
s.author = package['author']
|
|
12
|
-
s.homepage = package['homepage']
|
|
13
|
-
s.platforms = {
|
|
14
|
-
:ios => '15.1',
|
|
15
|
-
:tvos => '15.1'
|
|
16
|
-
}
|
|
17
|
-
s.swift_version = '5.4'
|
|
18
|
-
s.source = { git: 'https://github.com/kaspernj/flash-notifications' }
|
|
19
|
-
s.static_framework = true
|
|
20
|
-
|
|
21
|
-
s.dependency 'ExpoModulesCore'
|
|
22
|
-
|
|
23
|
-
# Swift/Objective-C compatibility
|
|
24
|
-
s.pod_target_xcconfig = {
|
|
25
|
-
'DEFINES_MODULE' => 'YES',
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}"
|
|
29
|
-
end
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import ExpoModulesCore
|
|
2
|
-
|
|
3
|
-
public class FlashNotificationsModule: Module {
|
|
4
|
-
// Each module class must implement the definition function. The definition consists of components
|
|
5
|
-
// that describes the module's functionality and behavior.
|
|
6
|
-
// See https://docs.expo.dev/modules/module-api for more details about available components.
|
|
7
|
-
public func definition() -> ModuleDefinition {
|
|
8
|
-
// Sets the name of the module that JavaScript code will use to refer to the module. Takes a string as an argument.
|
|
9
|
-
// Can be inferred from module's class name, but it's recommended to set it explicitly for clarity.
|
|
10
|
-
// The module will be accessible from `requireNativeModule('FlashNotifications')` in JavaScript.
|
|
11
|
-
Name("FlashNotifications")
|
|
12
|
-
|
|
13
|
-
// Sets constant properties on the module. Can take a dictionary or a closure that returns a dictionary.
|
|
14
|
-
Constants([
|
|
15
|
-
"PI": Double.pi
|
|
16
|
-
])
|
|
17
|
-
|
|
18
|
-
// Defines event names that the module can send to JavaScript.
|
|
19
|
-
Events("onChange")
|
|
20
|
-
|
|
21
|
-
// Defines a JavaScript synchronous function that runs the native code on the JavaScript thread.
|
|
22
|
-
Function("hello") {
|
|
23
|
-
return "Hello world! 👋"
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Defines a JavaScript function that always returns a Promise and whose native code
|
|
27
|
-
// is by default dispatched on the different thread than the JavaScript runtime runs on.
|
|
28
|
-
AsyncFunction("setValueAsync") { (value: String) in
|
|
29
|
-
// Send an event to JavaScript.
|
|
30
|
-
self.sendEvent("onChange", [
|
|
31
|
-
"value": value
|
|
32
|
-
])
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Enables the module to be used as a native view. Definition components that are accepted as part of the
|
|
36
|
-
// view definition: Prop, Events.
|
|
37
|
-
View(FlashNotificationsView.self) {
|
|
38
|
-
// Defines a setter for the `url` prop.
|
|
39
|
-
Prop("url") { (view: FlashNotificationsView, url: URL) in
|
|
40
|
-
if view.webView.url != url {
|
|
41
|
-
view.webView.load(URLRequest(url: url))
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
Events("onLoad")
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import ExpoModulesCore
|
|
2
|
-
import WebKit
|
|
3
|
-
|
|
4
|
-
// This view will be used as a native component. Make sure to inherit from `ExpoView`
|
|
5
|
-
// to apply the proper styling (e.g. border radius and shadows).
|
|
6
|
-
class FlashNotificationsView: ExpoView {
|
|
7
|
-
let webView = WKWebView()
|
|
8
|
-
let onLoad = EventDispatcher()
|
|
9
|
-
var delegate: WebViewDelegate?
|
|
10
|
-
|
|
11
|
-
required init(appContext: AppContext? = nil) {
|
|
12
|
-
super.init(appContext: appContext)
|
|
13
|
-
clipsToBounds = true
|
|
14
|
-
delegate = WebViewDelegate { url in
|
|
15
|
-
self.onLoad(["url": url])
|
|
16
|
-
}
|
|
17
|
-
webView.navigationDelegate = delegate
|
|
18
|
-
addSubview(webView)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
override func layoutSubviews() {
|
|
22
|
-
webView.frame = bounds
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
class WebViewDelegate: NSObject, WKNavigationDelegate {
|
|
27
|
-
let onUrlChange: (String) -> Void
|
|
28
|
-
|
|
29
|
-
init(onUrlChange: @escaping (String) -> Void) {
|
|
30
|
-
self.onUrlChange = onUrlChange
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation) {
|
|
34
|
-
if let url = webView.url {
|
|
35
|
-
onUrlChange(url.absoluteString)
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
package/peak_flow.yml
DELETED
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
import Configuration from "velocious/build/src/configuration.js"
|
|
2
|
-
import NodeEnvironmentHandler from "velocious/build/src/environment-handlers/node.js"
|
|
3
|
-
import TestFilesFinder from "velocious/build/src/testing/test-files-finder.js"
|
|
4
|
-
import TestRunner from "velocious/build/src/testing/test-runner.js"
|
|
5
|
-
import fs from "node:fs/promises"
|
|
6
|
-
import {execFileSync} from "node:child_process"
|
|
7
|
-
import path from "node:path"
|
|
8
|
-
|
|
9
|
-
const INCLUDE_TAG_FLAGS = new Set(["--tag", "--include-tag", "-t"])
|
|
10
|
-
const EXCLUDE_TAG_FLAGS = new Set(["--exclude-tag", "--skip-tag", "-x"])
|
|
11
|
-
|
|
12
|
-
const splitTags = (value) => {
|
|
13
|
-
if (!value) return []
|
|
14
|
-
|
|
15
|
-
return value
|
|
16
|
-
.split(",")
|
|
17
|
-
.map((tag) => tag.trim())
|
|
18
|
-
.filter(Boolean)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const parseTagFilters = (processArgs) => {
|
|
22
|
-
const includeTags = []
|
|
23
|
-
const excludeTags = []
|
|
24
|
-
const filteredProcessArgs = []
|
|
25
|
-
let inRestArgs = false
|
|
26
|
-
|
|
27
|
-
for (let i = 0; i < processArgs.length; i++) {
|
|
28
|
-
const arg = processArgs[i]
|
|
29
|
-
|
|
30
|
-
if (arg === "--") {
|
|
31
|
-
inRestArgs = true
|
|
32
|
-
filteredProcessArgs.push(arg)
|
|
33
|
-
continue
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
if (!inRestArgs) {
|
|
37
|
-
if (INCLUDE_TAG_FLAGS.has(arg)) {
|
|
38
|
-
const nextValue = processArgs[i + 1]
|
|
39
|
-
|
|
40
|
-
if (nextValue && !nextValue.startsWith("-")) {
|
|
41
|
-
includeTags.push(...splitTags(nextValue))
|
|
42
|
-
i++
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
continue
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (EXCLUDE_TAG_FLAGS.has(arg)) {
|
|
49
|
-
const nextValue = processArgs[i + 1]
|
|
50
|
-
|
|
51
|
-
if (nextValue && !nextValue.startsWith("-")) {
|
|
52
|
-
excludeTags.push(...splitTags(nextValue))
|
|
53
|
-
i++
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
continue
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (arg.startsWith("--tag=")) {
|
|
60
|
-
includeTags.push(...splitTags(arg.slice("--tag=".length)))
|
|
61
|
-
continue
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (arg.startsWith("--include-tag=")) {
|
|
65
|
-
includeTags.push(...splitTags(arg.slice("--include-tag=".length)))
|
|
66
|
-
continue
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (arg.startsWith("--exclude-tag=")) {
|
|
70
|
-
excludeTags.push(...splitTags(arg.slice("--exclude-tag=".length)))
|
|
71
|
-
continue
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (arg.startsWith("--skip-tag=")) {
|
|
75
|
-
excludeTags.push(...splitTags(arg.slice("--skip-tag=".length)))
|
|
76
|
-
continue
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
filteredProcessArgs.push(arg)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return {
|
|
84
|
-
includeTags: Array.from(new Set(includeTags)),
|
|
85
|
-
excludeTags: Array.from(new Set(excludeTags)),
|
|
86
|
-
filteredProcessArgs
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const main = async () => {
|
|
91
|
-
const processArgs = process.argv.slice(2)
|
|
92
|
-
|
|
93
|
-
const distPath = path.join(process.cwd(), "example", "dist")
|
|
94
|
-
try {
|
|
95
|
-
await fs.stat(distPath)
|
|
96
|
-
} catch {
|
|
97
|
-
execFileSync("npm", ["run", "export:web"], {stdio: "inherit"})
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const environmentHandler = new NodeEnvironmentHandler()
|
|
101
|
-
const configuration = new Configuration({
|
|
102
|
-
environment: "test",
|
|
103
|
-
environmentHandler,
|
|
104
|
-
directory: process.cwd(),
|
|
105
|
-
database: {test: {}}
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
configuration.setCurrent()
|
|
109
|
-
|
|
110
|
-
let directory
|
|
111
|
-
const directories = []
|
|
112
|
-
|
|
113
|
-
if (process.env.VELOCIOUS_TEST_DIR) {
|
|
114
|
-
directory = process.env.VELOCIOUS_TEST_DIR
|
|
115
|
-
directories.push(process.env.VELOCIOUS_TEST_DIR)
|
|
116
|
-
} else {
|
|
117
|
-
directory = process.cwd()
|
|
118
|
-
directories.push(process.cwd())
|
|
119
|
-
directories.push(`${process.cwd()}/__tests__`)
|
|
120
|
-
directories.push(`${process.cwd()}/tests`)
|
|
121
|
-
directories.push(`${process.cwd()}/spec`)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const {includeTags, excludeTags, filteredProcessArgs} = parseTagFilters(processArgs)
|
|
125
|
-
const testFilesFinder = new TestFilesFinder({
|
|
126
|
-
directory,
|
|
127
|
-
directories,
|
|
128
|
-
processArgs: filteredProcessArgs
|
|
129
|
-
})
|
|
130
|
-
const testFiles = await testFilesFinder.findTestFiles()
|
|
131
|
-
const testRunner = new TestRunner({configuration, excludeTags, includeTags, testFiles})
|
|
132
|
-
|
|
133
|
-
let signalHandled = false
|
|
134
|
-
const handleSignal = async (signal) => {
|
|
135
|
-
if (signalHandled) return
|
|
136
|
-
|
|
137
|
-
signalHandled = true
|
|
138
|
-
console.error(`\nReceived ${signal}, running afterAll hooks before exit...`)
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
await testRunner.runAfterAllsForActiveScopes()
|
|
142
|
-
} catch (error) {
|
|
143
|
-
console.error("Failed while running afterAll hooks:", error)
|
|
144
|
-
} finally {
|
|
145
|
-
process.exit(130)
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
process.once("SIGINT", () => { void handleSignal("SIGINT") })
|
|
150
|
-
process.once("SIGTERM", () => { void handleSignal("SIGTERM") })
|
|
151
|
-
|
|
152
|
-
await testRunner.prepare()
|
|
153
|
-
|
|
154
|
-
if (testRunner.getTestsCount() === 0) {
|
|
155
|
-
throw new Error(`${testRunner.getTestsCount()} tests was found in ${testFiles.length} file(s)`)
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
await testRunner.run()
|
|
159
|
-
|
|
160
|
-
const executedTests = testRunner.getExecutedTestsCount()
|
|
161
|
-
|
|
162
|
-
if ((includeTags.length > 0 || excludeTags.length > 0) && executedTests === 0) {
|
|
163
|
-
console.error("\nNo tests matched the provided tag filters")
|
|
164
|
-
process.exit(1)
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (testRunner.isFailed()) {
|
|
168
|
-
console.error(
|
|
169
|
-
`\nTest run failed with ${testRunner.getFailedTests()} failed tests and ${testRunner.getSuccessfulTests()} successfull`
|
|
170
|
-
)
|
|
171
|
-
process.exit(1)
|
|
172
|
-
} else if (testRunner.areAnyTestsFocussed()) {
|
|
173
|
-
console.error(
|
|
174
|
-
`\nFocussed run with ${testRunner.getFailedTests()} failed tests and ${testRunner.getSuccessfulTests()} successfull`
|
|
175
|
-
)
|
|
176
|
-
process.exit(1)
|
|
177
|
-
} else {
|
|
178
|
-
console.log(`\nTest run succeeded with ${testRunner.getSuccessfulTests()} successful tests`)
|
|
179
|
-
process.exit(0)
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
main().catch((error) => {
|
|
184
|
-
console.error(error)
|
|
185
|
-
process.exit(1)
|
|
186
|
-
})
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import "velocious/build/src/testing/test.js"
|
|
4
|
-
import SystemTest from "system-testing/build/system-test.js"
|
|
5
|
-
import SystemTestHelper from "./support/system-test-helper.js"
|
|
6
|
-
import wait from "awaitery/build/wait.js"
|
|
7
|
-
|
|
8
|
-
SystemTest.rootPath = "/?systemTest=true"
|
|
9
|
-
|
|
10
|
-
const systemTestHelper = new SystemTestHelper()
|
|
11
|
-
systemTestHelper.installHooks()
|
|
12
|
-
|
|
13
|
-
describe("Flash notifications", () => {
|
|
14
|
-
it("dismisses a notification when pressed", async () => {
|
|
15
|
-
await SystemTest.run(async (systemTest) => {
|
|
16
|
-
await systemTest.visit("/")
|
|
17
|
-
|
|
18
|
-
const triggerButton = await systemTest.findByTestID("flashNotifications/showNotification")
|
|
19
|
-
await systemTest.click(triggerButton)
|
|
20
|
-
|
|
21
|
-
const notificationMessage = await systemTest.findByTestID("notification-message", {useBaseSelector: false})
|
|
22
|
-
const notificationText = await notificationMessage.getText()
|
|
23
|
-
expect(notificationText).toEqual("Dismiss me")
|
|
24
|
-
const notificationContainer = await systemTest.findByTestID("flash-notifications-notification", {useBaseSelector: false})
|
|
25
|
-
|
|
26
|
-
await systemTest.click(notificationContainer)
|
|
27
|
-
await systemTest.waitForNoSelector("[data-testid='flash-notifications-notification']", {useBaseSelector: false})
|
|
28
|
-
})
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it("auto dismisses a notification after a delay", async () => {
|
|
32
|
-
await SystemTest.run(async (systemTest) => {
|
|
33
|
-
await systemTest.visit("/")
|
|
34
|
-
|
|
35
|
-
const triggerButton = await systemTest.findByTestID("flashNotifications/showNotification")
|
|
36
|
-
await systemTest.click(triggerButton)
|
|
37
|
-
|
|
38
|
-
const notificationMessage = await systemTest.findByTestID("notification-message", {useBaseSelector: false})
|
|
39
|
-
const notificationText = await notificationMessage.getText()
|
|
40
|
-
expect(notificationText).toEqual("Dismiss me")
|
|
41
|
-
|
|
42
|
-
await wait(4500)
|
|
43
|
-
await systemTest.waitForNoSelector("[data-testid='notification-message']", {useBaseSelector: false})
|
|
44
|
-
})
|
|
45
|
-
})
|
|
46
|
-
})
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import fs from "node:fs/promises"
|
|
4
|
-
import path from "node:path"
|
|
5
|
-
import {fileURLToPath} from "node:url"
|
|
6
|
-
|
|
7
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Ensures the dummy app's dist folder is served for system tests.
|
|
11
|
-
*/
|
|
12
|
-
export default class DummyHttpServerEnvironment {
|
|
13
|
-
constructor({host = "dist"} = {}) {
|
|
14
|
-
this.host = host
|
|
15
|
-
this.dummyAppRoot = path.resolve(__dirname, "..", "..", "example")
|
|
16
|
-
/** @type {string | undefined} */
|
|
17
|
-
this.originalCwd = undefined
|
|
18
|
-
this.started = false
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** @returns {Promise<void>} */
|
|
22
|
-
async start() {
|
|
23
|
-
if (this.started) return
|
|
24
|
-
|
|
25
|
-
this.originalCwd = process.cwd()
|
|
26
|
-
await this.ensureDistFolder()
|
|
27
|
-
process.chdir(this.dummyAppRoot)
|
|
28
|
-
process.env.SYSTEM_TEST_HOST ||= this.host
|
|
29
|
-
this.started = true
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** @returns {Promise<void>} */
|
|
33
|
-
async stop() {
|
|
34
|
-
if (!this.started) return
|
|
35
|
-
if (this.originalCwd) process.chdir(this.originalCwd)
|
|
36
|
-
this.started = false
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** @returns {Promise<void>} */
|
|
40
|
-
async ensureDistFolder() {
|
|
41
|
-
const distPath = path.join(this.dummyAppRoot, "dist")
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
const stats = await fs.stat(distPath)
|
|
45
|
-
if (!stats.isDirectory()) {
|
|
46
|
-
throw new Error(`Expected dist path to be a directory: ${distPath}`)
|
|
47
|
-
}
|
|
48
|
-
} catch (error) {
|
|
49
|
-
throw new Error(`Missing dist folder for dummy app at ${distPath}: ${error instanceof Error ? error.message : error}`)
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
|
-
import wait from "awaitery/build/wait.js"
|
|
4
|
-
|
|
5
|
-
import SystemTest from "system-testing/build/system-test.js"
|
|
6
|
-
import DummyHttpServerEnvironment from "./dummy-http-server.js"
|
|
7
|
-
|
|
8
|
-
const globalState = /** @type {any} */ (globalThis)
|
|
9
|
-
const sharedState = globalState.__systemTestHelperState ??= {
|
|
10
|
-
refCount: 0,
|
|
11
|
-
started: false,
|
|
12
|
-
/** @type {SystemTest | undefined} */
|
|
13
|
-
systemTest: undefined,
|
|
14
|
-
dummyHttpServerEnvironment: new DummyHttpServerEnvironment()
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export default class SystemTestHelper {
|
|
18
|
-
constructor({debug = process.env.SYSTEM_TEST_DEBUG === "true"} = {}) {
|
|
19
|
-
this.debug = debug
|
|
20
|
-
this.dummyHttpServerEnvironment = sharedState.dummyHttpServerEnvironment
|
|
21
|
-
this.systemTest = sharedState.systemTest
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** @param {...any} args */
|
|
25
|
-
debugLog(...args) { if (this.debug) console.log(...args) }
|
|
26
|
-
|
|
27
|
-
installHooks() {
|
|
28
|
-
beforeAll(async () => {
|
|
29
|
-
await this.start()
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
afterAll(async () => {
|
|
33
|
-
await this.stop()
|
|
34
|
-
})
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/** @returns {Promise<void>} */
|
|
38
|
-
async start() {
|
|
39
|
-
sharedState.refCount += 1
|
|
40
|
-
if (sharedState.started) {
|
|
41
|
-
this.systemTest = sharedState.systemTest
|
|
42
|
-
return
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
sharedState.started = true
|
|
46
|
-
this.debugLog("[system-test] beforeAll: starting dummy HTTP env")
|
|
47
|
-
try {
|
|
48
|
-
await this.dummyHttpServerEnvironment.start()
|
|
49
|
-
await wait(1000)
|
|
50
|
-
|
|
51
|
-
this.debugLog("[system-test] beforeAll: creating SystemTest")
|
|
52
|
-
this.systemTest = SystemTest.current({
|
|
53
|
-
debug: this.debug,
|
|
54
|
-
host: "127.0.0.1",
|
|
55
|
-
port: 3601,
|
|
56
|
-
httpHost: "0.0.0.0",
|
|
57
|
-
httpPort: 3602,
|
|
58
|
-
errorFilter: (error) => {
|
|
59
|
-
if (typeof error?.value?.[0] === "string" && error.value[0].includes("Uncaught Error: Minified React error #418; visit")) return false
|
|
60
|
-
return true
|
|
61
|
-
}
|
|
62
|
-
})
|
|
63
|
-
sharedState.systemTest = this.systemTest
|
|
64
|
-
this.debugLog("[system-test] beforeAll: starting SystemTest")
|
|
65
|
-
await this.systemTest.start()
|
|
66
|
-
this.debugLog("[system-test] beforeAll: SystemTest started")
|
|
67
|
-
} catch (error) {
|
|
68
|
-
sharedState.started = false
|
|
69
|
-
sharedState.refCount = Math.max(0, sharedState.refCount - 1)
|
|
70
|
-
console.error("[system-test] beforeAll error", error)
|
|
71
|
-
throw error
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/** @returns {Promise<void>} */
|
|
76
|
-
async stop() {
|
|
77
|
-
if (!sharedState.started) return
|
|
78
|
-
sharedState.refCount = Math.max(0, sharedState.refCount - 1)
|
|
79
|
-
if (sharedState.refCount > 0) return
|
|
80
|
-
|
|
81
|
-
this.debugLog("[system-test] afterAll: stopping SystemTest and dummy HTTP env")
|
|
82
|
-
try {
|
|
83
|
-
await this.systemTest?.stop()
|
|
84
|
-
await this.dummyHttpServerEnvironment.stop()
|
|
85
|
-
this.debugLog("[system-test] afterAll: teardown complete")
|
|
86
|
-
sharedState.started = false
|
|
87
|
-
sharedState.systemTest = undefined
|
|
88
|
-
} catch (error) {
|
|
89
|
-
console.error("[system-test] afterAll error", error)
|
|
90
|
-
throw error
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** @returns {SystemTest} */
|
|
95
|
-
getSystemTest() {
|
|
96
|
-
if (!this.systemTest) throw new Error("SystemTest hasn't been started yet")
|
|
97
|
-
return this.systemTest
|
|
98
|
-
}
|
|
99
|
-
}
|
package/src/configuration.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
if (!globalThis.flashNotificationsConfiguration) {
|
|
2
|
-
globalThis.flashNotificationsConfiguration = {
|
|
3
|
-
debug: false,
|
|
4
|
-
translate: (msgId, args) => args?.defaultValue || msgId
|
|
5
|
-
}
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const configuration = globalThis.flashNotificationsConfiguration
|
|
9
|
-
|
|
10
|
-
export default configuration
|