Sam się zaorałem.
Pisząc testy w Jest, utworzyłem sobie na potrzeby testów pewną strukturę danych (tablicę tablic), do której dodałem taką oto asercję:
expect(whatHappened).toEqual([
['UPDATE', {a: 10}, {a: 10}],
['EFFECTS', {a: 10, b: 11}, {a: 10, b: 11}],
['UPDATE', {a: 10, b: 11}, {a: 10, b: 11}]
['EFFECTS', {a: 10, b: 11}, {a: 10, b: 11}],
]);
I testy nie przechodziły, pomimo, że powinny były przejść! Aż sprawdzałem JSON.stringify(whatHappened, 0, 2)
i przyglądałem się po kilka razy, wszystko wydawało się w porządku. Nawet sprawdzałem kolejne elementy tablicy po kolei i wszystko przechodziło. Tylko jak się dało całą tablicę naraz, to nie przeszło. I dawało w diffie, że gdzieś jest undefined
, mimo, że go przecież nie było!
Więc zmieniłem expect z Jest, na assert.deepStrictEqual
, mając nadzieję, że to bug w Jest. Bo przecież jak to tak? Jednak assert.deepStrictEqual
także wywalało mi błąd, jednak nieco czytelniej mi pokazywało diffa.
fragment tego diffa (wreszcie załapałem, gdzie się pojawia to undefined.
Array [
"EFFECTS",
Object {
"a": 10,
"b": 11,
},
Object {
"a": 10,
"b": 11,
},
],
- undefined,
+ Array [
+ "UPDATE",
+ Object {
+ "a": 10,
+ "b": 11,
+ },
+ Object {
+ "a": 10,
+ "b": 11,
+ },
+ ],
Jak widzimy, między dwoma elementami tablicy nijak skądś wyskakuje undefined
. Wiecie już?
.
.
.
.
.
.
.
.
.
Otóż, ku mojemu przerażeniu dokonałem straszliwego odkrycia. Zapomniałem przecinka
['UPDATE', {a: 10, b: 11}, {a: 10, b: 11}]
['EFFECTS', {a: 10, b: 11}, {a: 10, b: 11}],
i tutaj szybko wykoncypowałem, że JS []
wziął za indeks tablicy, a nie za kolejny element, więc dla JS te dwa elementy to było coś jak to:
jakasTablica = ['UPDATE', {a: 10, b: 11}, {a: 10, b: 11}]; // pierwszy element
jakasTablica['EFFECTS', {a: 10, b: 11}, {a: 10, b: 11}], // drugi element
Jednak dalej coś się nie zgadza. Przecież w JS można dawać tylko jeden argument jako indeks []
. no ale tutaj z górki. Po prostu w JS wyrażenie może zawierać przecinki, ale liczy się ostatnia wartość, czyli:
alert(('Hello', 'World')); // równoważne w tym wypadku alert('World');
wyświetli samo World
(zwróćcie uwagę, że dałem tu dodatkowy nawias, bo bez tego potraktowałby wartość po przecinku jako separator między argumentami, więc wyświetliłby samo Hello
.
Czyli JS potrafi być wredny. Nie poprzez brak typów, ale przez to, że wszystko może być wszystkim, a wiele znaków ma podwójne znaczenie (tutaj []
, ale także {}
rodzi tego typu problemy, podobnie jak ()
czy +
...). Swoją drogą ciekawe, czy TypeScript i statyczne typowanie by mnie tutaj uratowało w tym momencie? Możliwe, mogłoby zaalarmować, że coś jest nie tak, ale czy dałoby mi na tyle czytelny komunikat, żebym zakumał od razu, co robię źle? Bo, że "coś nie działało", to mnie ostrzegł już Jest, ale to był komunikat, który wcale niewiele mi pomógł, poza tym, że wiedziałem, że coś nie działa, a powinno).