Skip to content

Commit 5a7556e

Browse files
authored
Get JavaScript to parity with Java (#62)
1 parent eaa6b67 commit 5a7556e

20 files changed

+1026
-194
lines changed

.github/workflows/release-npm.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
- uses: actions/checkout@v4
1414
- uses: actions/setup-node@v4
1515
with:
16-
node-version: '16'
16+
node-version: '22'
1717
cache: 'npm'
1818
cache-dependency-path: javascript/package-lock.json
1919
- run: npm install-test

.github/workflows/test-javascript.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ jobs:
1818
matrix:
1919
os:
2020
- ubuntu-latest
21-
node-version: ["16.x", "17.x", "18.x"]
21+
node-version: ["18.x", "20.x", "22.x"]
2222
include:
2323
- os: windows-latest
24-
node-version: "18.x"
24+
node-version: "22.x"
2525
- os: macos-latest
26-
node-version: "18.x"
26+
node-version: "22.x"
2727

2828
steps:
2929
- uses: actions/checkout@v4

CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
88
## [Unreleased]
99

1010
### Added
11+
- New methods in JavaScript implementation to match Java ([#62](https://github.com/cucumber/query/pull/62))
1112
- Update dependency @cucumber/messages to v26 ((#52)[https://github.com/cucumber/query/pull/52])
1213
- Update dependency io.cucumber:messages up to v26 ((#53)[https://github.com/cucumber/query/pull/53])
1314

15+
### Changed
16+
- BREAKING CHANGE: `countMostSevereTestStepResultStatus` now returns `EnumMap` with all statuses regardless of count ([#62](https://github.com/cucumber/query/pull/62))
17+
- BREAKING CHANGE: `findAllTestCaseStarted` now omits `TestCaseStarted` messages where there is or will be another attempt ([#62](https://github.com/cucumber/query/pull/62))
18+
- BREAKING CHANGE: Rename `findMostSevereTestStepResulBy` to `findMostSevereTestStepResultBy` ([#62](https://github.com/cucumber/query/pull/62))
19+
20+
### Removed
21+
- BREAKING CHANGE: Remove support for Node.js 16.x and 17.x ([#62](https://github.com/cucumber/query/pull/62))
22+
1423
## [12.2.0] - 2024-06-22
1524
### Changed
1625
- Include pickle name if parameterized ((#44)[https://github.com/cucumber/query/pull/44])

CONTRIBUTING.md

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Contributing
2+
3+
For general guidance on contributing to Cucumber, see https://github.com/cucumber/.github/blob/main/CONTRIBUTING.md
4+
5+
## Adding or changing query methods
6+
7+
This is a polyglot repo with several languages adhering to a common suite of acceptance tests. A change should be made consistently across all languages. Currently, the list is:
8+
9+
- Java (reference)
10+
- JavaScript
11+
12+
Java is the reference implementation in the sense that it is responsible for generating the fixtures that are used in the acceptance tests to verify all implementations.
13+
14+
So your playbook for adding a method would be something like:
15+
16+
1. Add the method in `Query.Java` with test(s) in `QueryTest.java`
17+
2. Extend `QueryAcceptanceTest.java` to include verifications for the new method
18+
3. Run `QueryAcceptanceTest::updateExpectedQueryResultFiles` to regenerate the fixtures
19+
4. Implement other languages
20+
21+
## Types
22+
23+
Choosing which type to use in another language based on what we did in Java is an inexact science. This table defines all the decisions we've made so far:
24+
25+
| Java | JavaScript |
26+
|---------------------|-------------------------|
27+
| `Optional<T>` | `T \| undefined`[^1] |
28+
| `List<T>` | `ReadonlyArray<T>` |
29+
| `Map<K, V>` | `Map<K, V>` |
30+
| `EnumMap<K, V>` | `Record<K, V>` |
31+
| `List<Entry<T, V>>` | `ReadonlyArray<[T, V]>` |
32+
33+
[^1]: See <https://github.com/sindresorhus/meta/discussions/7>

java/src/main/java/io/cucumber/query/Query.java

+16-13
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,14 @@
2323
import io.cucumber.messages.types.Timestamp;
2424

2525
import java.time.Duration;
26+
import java.util.*;
2627
import java.util.AbstractMap.SimpleEntry;
27-
import java.util.ArrayList;
28-
import java.util.Comparator;
29-
import java.util.Deque;
30-
import java.util.LinkedHashMap;
31-
import java.util.List;
32-
import java.util.Map;
3328
import java.util.Map.Entry;
34-
import java.util.Optional;
3529
import java.util.concurrent.ConcurrentHashMap;
3630
import java.util.concurrent.ConcurrentLinkedDeque;
3731
import java.util.function.BiFunction;
3832
import java.util.function.Supplier;
33+
import java.util.stream.Collectors;
3934

4035
import static java.util.Collections.emptyList;
4136
import static java.util.Comparator.comparing;
@@ -61,6 +56,8 @@
6156
* @see <a href="https://github.com/cucumber/messages?tab=readme-ov-file#message-overview">Cucumber Messages - Message Overview</a>
6257
*/
6358
public final class Query {
59+
private static final Map<TestStepResultStatus, Long> ZEROES_BY_TEST_STEP_RESULT_STATUSES = Arrays.stream(TestStepResultStatus.values())
60+
.collect(Collectors.toMap(identity(), (s) -> 0L));
6461
private final Comparator<TestStepResult> testStepResultComparator = nullsFirst(comparing(o -> o.getStatus().ordinal()));
6562
private final Deque<TestCaseStarted> testCaseStarted = new ConcurrentLinkedDeque<>();
6663
private final Map<String, TestCaseFinished> testCaseFinishedByTestCaseStartedId = new ConcurrentHashMap<>();
@@ -74,13 +71,15 @@ public final class Query {
7471
private TestRunStarted testRunStarted;
7572
private TestRunFinished testRunFinished;
7673

77-
public Map<TestStepResultStatus, Long> countMostSevereTestStepResultStatus() {
78-
return findAllTestCaseStarted().stream()
79-
.map(this::findMostSevereTestStepResulBy)
74+
public EnumMap<TestStepResultStatus, Long> countMostSevereTestStepResultStatus() {
75+
final EnumMap<TestStepResultStatus, Long> results = new EnumMap<>(ZEROES_BY_TEST_STEP_RESULT_STATUSES);
76+
results.putAll(findAllTestCaseStarted().stream()
77+
.map(this::findMostSevereTestStepResultBy)
8078
.filter(Optional::isPresent)
8179
.map(Optional::get)
8280
.map(TestStepResult::getStatus)
83-
.collect(groupingBy(identity(), LinkedHashMap::new, counting()));
81+
.collect(groupingBy(identity(), LinkedHashMap::new, counting())));
82+
return results;
8483
}
8584

8685
public int countTestCasesStarted() {
@@ -100,7 +99,11 @@ public List<PickleStep> findAllPickleSteps() {
10099
}
101100

102101
public List<TestCaseStarted> findAllTestCaseStarted() {
103-
return new ArrayList<>(testCaseStarted);
102+
return this.testCaseStarted.stream()
103+
.filter(testCaseStarted1 -> !findTestCaseFinishedBy(testCaseStarted1)
104+
.filter(TestCaseFinished::getWillBeRetried)
105+
.isPresent())
106+
.collect(toList());
104107
}
105108

106109
public Map<Optional<Feature>, List<TestCaseStarted>> findAllTestCaseStartedGroupedByFeature() {
@@ -136,7 +139,7 @@ public Optional<Feature> findFeatureBy(TestCaseStarted testCaseStarted) {
136139
return findLineageBy(testCaseStarted).flatMap(Lineage::feature);
137140
}
138141

139-
public Optional<TestStepResult> findMostSevereTestStepResulBy(TestCaseStarted testCaseStarted) {
142+
public Optional<TestStepResult> findMostSevereTestStepResultBy(TestCaseStarted testCaseStarted) {
140143
requireNonNull(testCaseStarted);
141144
return findTestStepsFinishedBy(testCaseStarted)
142145
.stream()

java/src/test/java/io/cucumber/query/QueryAcceptanceTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ private static Map<String, Object> createQueryResults(Query query) {
115115
.map(query::findFeatureBy)
116116
.map(feature -> feature.map(Feature::getName))
117117
.collect(toList()));
118-
results.put("findMostSevereTestStepResulBy", query.findAllTestCaseStarted().stream()
119-
.map(query::findMostSevereTestStepResulBy)
118+
results.put("findMostSevereTestStepResultBy", query.findAllTestCaseStarted().stream()
119+
.map(query::findMostSevereTestStepResultBy)
120120
.map(testStepResult -> testStepResult.map(TestStepResult::getStatus))
121121
.collect(toList()));
122122

java/src/test/java/io/cucumber/query/QueryTest.java

+18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.cucumber.query;
22

33
import io.cucumber.messages.types.Envelope;
4+
import io.cucumber.messages.types.TestCaseFinished;
45
import io.cucumber.messages.types.TestCaseStarted;
56
import io.cucumber.messages.types.Timestamp;
67
import org.junit.jupiter.api.Test;
@@ -27,6 +28,23 @@ void retainsInsertionOrderForTestCaseStarted() {
2728
assertThat(query.findAllTestCaseStarted()).containsExactly(a, b, c);
2829
}
2930

31+
@Test
32+
void omitsTestCaseStartedIfFinishedAndWillBeRetried() {
33+
TestCaseStarted a = new TestCaseStarted(0L, randomId(), randomId(), "main", new Timestamp(0L, 0L));
34+
TestCaseFinished b = new TestCaseFinished(a.getId(), new Timestamp(0L, 0L), true);
35+
TestCaseStarted c = new TestCaseStarted(0L, randomId(), randomId(), "main", new Timestamp(0L, 0L));
36+
TestCaseFinished d = new TestCaseFinished(c.getId(), new Timestamp(0L, 0L), false);
37+
38+
Stream.of(a, c)
39+
.map(Envelope::of)
40+
.forEach(query::update);
41+
Stream.of(b, d)
42+
.map(Envelope::of)
43+
.forEach(query::update);
44+
45+
assertThat(query.findAllTestCaseStarted()).containsExactly(c);
46+
}
47+
3048
private static String randomId() {
3149
return UUID.randomUUID().toString();
3250
}

0 commit comments

Comments
 (0)