@rbxts/specium 1.0.0 → 1.1.0

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/lib/index.d.ts CHANGED
@@ -7,6 +7,7 @@ interface SpeciumRunResult {
7
7
  total: number;
8
8
  passed: number;
9
9
  failed: number;
10
+ skipped: number;
10
11
  suites: SpeciumSuiteResult[];
11
12
  }
12
13
 
@@ -25,6 +26,10 @@ interface SpeciumTestResult {
25
26
  interface SpeciumSuiteContext {
26
27
  it(name: string, fn: () => SpeciumResult | void): void;
27
28
  describe(name: string, fn: (ctx: SpeciumSuiteContext) => void): void;
29
+ beforeAll(fn: () => void): void;
30
+ afterAll(fn: () => void): void;
31
+ beforeEach(fn: () => void): void;
32
+ afterEach(fn: () => void): void;
28
33
  }
29
34
 
30
35
  interface SpeciumSuite {
@@ -54,9 +59,7 @@ interface SpeciumMatchers extends SpeciumMatchersRaw {
54
59
  interface Specium {
55
60
  suite(name: string, fn: (ctx: SpeciumSuiteContext) => void): SpeciumSuite;
56
61
  run(suite: SpeciumSuite): [string, SpeciumRunResult];
57
- runTests(
58
- testsFolder: Instance | Instance[],
59
- ): [string, Array<SpeciumRunResult>];
62
+ runTests(testsFolder: Instance | Instance[]): [string, SpeciumRunResult[]];
60
63
  expect(received: unknown): SpeciumMatchers;
61
64
  success(message: string): SpeciumResult;
62
65
  error(message: string): SpeciumResult;
package/lib/init.luau CHANGED
@@ -10,15 +10,21 @@ local Specium = {}
10
10
  type SpeciumTest = {
11
11
  name: string,
12
12
  fn: () -> SpeciumResult,
13
+ skipped: boolean,
13
14
  }
14
15
  type SpeciumSuite = {
15
16
  name: string,
16
17
  tests: { SpeciumTest },
17
18
  subSuites: { SpeciumSuite },
19
+ beforeAll: (() -> ())?,
20
+ afterAll: (() -> ())?,
21
+ beforeEach: (() -> ())?,
22
+ afterEach: (() -> ())?,
18
23
  }
19
24
  type SpeciumTestResult = {
20
25
  name: string,
21
26
  success: boolean,
27
+ skipped: boolean,
22
28
  message: string,
23
29
  }
24
30
  type SpeciumSuiteResult = {
@@ -48,17 +54,28 @@ export type SpeciumRunResult = {
48
54
  total: number,
49
55
  passed: number,
50
56
  failed: number,
57
+ skipped: number,
51
58
  suites: { SpeciumSuiteResult },
52
59
  }
53
60
  --[=[
54
61
  @interface SpeciumSuiteContext
55
62
  @within Specium
56
63
  .it (name: string, fn: () -> SpeciumResult) -> () -- Registers a test case inside the current suite
64
+ .skip (name: string, fn () -> SpeciumResult) -> () -- Registers a test case that will be skipped when the suite runs
57
65
  .describe (name: string, fn: (SpeciumSuiteContext) -> ()) -> () -- Creates a nested sub-suite
66
+ .beforeAll (() -> ())? -- Runs once before all tests in the suite
67
+ .afterAll (() -> ())? -- Runs once after all tests in the suite
68
+ .beforeEach (() -> ())? -- Runs before each test in the suite
69
+ .afterEach (() -> ())? -- Runs after each test in the suite
58
70
  ]=]
59
71
  export type SpeciumSuiteContext = {
60
72
  it: (name: string, fn: () -> SpeciumResult) -> (),
73
+ skip: (name: string, fn: () -> SpeciumResult) -> (),
61
74
  describe: (name: string, fn: (SpeciumSuiteContext) -> ()) -> (),
75
+ beforeAll: (() -> ()) -> (),
76
+ afterAll: (() -> ()) -> (),
77
+ beforeEach: (() -> ()) -> (),
78
+ afterEach: (() -> ()) -> (),
62
79
  }
63
80
 
64
81
  --[=[
@@ -100,6 +117,15 @@ function Specium.suite(name: string, fn: (SpeciumSuiteContext) -> ()): SpeciumSu
100
117
  table.insert(currentSuite.tests, {
101
118
  name = name,
102
119
  fn = fn,
120
+ skipped = false,
121
+ })
122
+ end
123
+
124
+ function ctx.skip(name: string, fn: () -> SpeciumResult)
125
+ table.insert(currentSuite.tests, {
126
+ name = name,
127
+ fn = fn,
128
+ skipped = true,
103
129
  })
104
130
  end
105
131
 
@@ -115,6 +141,17 @@ function Specium.suite(name: string, fn: (SpeciumSuiteContext) -> ()): SpeciumSu
115
141
  fn(createContext(newSuite))
116
142
  end
117
143
 
144
+ local function createSuiteSetter(key: string)
145
+ ctx[key] = function(value: any)
146
+ currentSuite[key] = value
147
+ end
148
+ end
149
+
150
+ createSuiteSetter("beforeAll")
151
+ createSuiteSetter("afterAll")
152
+ createSuiteSetter("beforeEach")
153
+ createSuiteSetter("afterEach")
154
+
118
155
  return ctx
119
156
  end
120
157
 
@@ -147,6 +184,7 @@ end
147
184
  function Specium.run(suite: SpeciumSuite): (string, SpeciumRunResult)
148
185
  local total = 0
149
186
  local passed = 0
187
+ local skipped = 0
150
188
 
151
189
  local output = "\n"
152
190
 
@@ -154,6 +192,7 @@ function Specium.run(suite: SpeciumSuite): (string, SpeciumRunResult)
154
192
  total = 0,
155
193
  passed = 0,
156
194
  failed = 0,
195
+ skipped = 0,
157
196
  suites = {},
158
197
  }
159
198
 
@@ -169,10 +208,40 @@ function Specium.run(suite: SpeciumSuite): (string, SpeciumRunResult)
169
208
 
170
209
  output ..= `{string.rep(" ", depth - 1)}> {currentSuite.name}\n`
171
210
 
211
+ local function opcall(fn: (() -> ())?, hookName: string)
212
+ if not fn then
213
+ return
214
+ end
215
+
216
+ local ok, err = xpcall(fn, function(e)
217
+ return `{e}\n{debug.traceback()}`
218
+ end)
219
+
220
+ if not ok then
221
+ warn(`[Specium] {hookName} failed in "{currentSuite.name}": {err}`)
222
+ end
223
+ end
224
+
225
+ opcall(currentSuite.beforeAll, "beforeAll")
226
+
172
227
  for _, test in currentSuite.tests do
173
228
  total += 1
174
229
 
230
+ if test.skipped then
231
+ skipped += 1
232
+ output ..= `{indent}[Skip] {test.name}\n`
233
+ table.insert(suiteResult.tests, {
234
+ name = test.name,
235
+ success = false,
236
+ message = "skipped",
237
+ skipped = true,
238
+ })
239
+ continue
240
+ end
241
+
242
+ opcall(currentSuite.beforeEach, "beforeEach")
175
243
  local ok, result = pcall(test.fn)
244
+ opcall(currentSuite.afterEach, "afterEach")
176
245
 
177
246
  if not ok then
178
247
  result = Specium.error(tostring(result))
@@ -191,6 +260,7 @@ function Specium.run(suite: SpeciumSuite): (string, SpeciumRunResult)
191
260
  name = test.name,
192
261
  success = result.success,
193
262
  message = result.message,
263
+ skipped = false,
194
264
  })
195
265
  end
196
266
 
@@ -199,6 +269,8 @@ function Specium.run(suite: SpeciumSuite): (string, SpeciumRunResult)
199
269
  table.insert(suiteResult.subSuites, subResult)
200
270
  end
201
271
 
272
+ opcall(currentSuite.afterAll, "afterAll")
273
+
202
274
  return suiteResult
203
275
  end
204
276
 
@@ -206,11 +278,26 @@ function Specium.run(suite: SpeciumSuite): (string, SpeciumRunResult)
206
278
 
207
279
  results.total = total
208
280
  results.passed = passed
209
- results.failed = total - passed
281
+ results.failed = total - passed - skipped
282
+ results.skipped = skipped
210
283
  results.suites = { rootResult }
211
284
 
212
285
  output ..= "\n\nResult:\n"
213
- output ..= total > 0 and `{passed}/{total} ({math.round(passed / total * 1000) / 10}%) tests passed` or "no tests found"
286
+ if total > 0 then
287
+ local ran = total - skipped
288
+ local summary
289
+ if ran > 0 then
290
+ summary = `{passed}/{ran} ({math.round(passed / ran * 1000) / 10}%) tests passed`
291
+ else
292
+ summary = "all tests skipped"
293
+ end
294
+ if skipped > 0 then
295
+ summary ..= `, {skipped} skipped`
296
+ end
297
+ output ..= summary
298
+ else
299
+ output ..= "no tests found"
300
+ end
214
301
 
215
302
  return output, results
216
303
  end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rbxts/specium",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "A simple and flexible testing framework for Roblox",
5
5
  "main": "lib/init.luau",
6
6
  "types": "lib/index.d.ts",