├── .babelrc
├── .eslintrc.json
├── .github
└── FUNDING.yml
├── .gitignore
├── .travis.yml
├── LICENSE.txt
├── README.md
├── package.json
├── src
├── bingo
│ └── bingo.js
├── fibonacci
│ └── fibonacci.js
├── find-the-rigth-triangle
│ └── find-the-right-triangle.js
├── fizz-buzz
│ └── fizz-buzz.js
├── greeting
│ └── greeting.js
├── index.js
├── maxibon
│ └── maxibon.js
├── potter
│ └── potter.js
├── prime-factors
│ └── prime-factors.js
├── rock-paper-scissors
│ └── rock-paper-scissors.js
├── roman-numerals
│ └── roman-numerals.js
└── string-calculator
│ └── string-calculator.js
├── test
├── bingo
│ └── bingo.spec.js
├── bootload.js
├── es6katas
│ ├── 1-TemplateStringsTest.js
│ ├── 10-DestructuringArraysTest.js
│ ├── 11-DestructuringStringsTest.js
│ ├── 12-DestructuringObjectsTest.js
│ ├── 13-DestructuringDefaults.js
│ ├── 14-DestructuringParametersTest.js
│ ├── 15-DestructuringAssignTest.js
│ ├── 16-ObjectLiteralComputedPropertiesTest.js
│ ├── 17-UnicodeInStringsTest.js
│ ├── 18-RestAsParameterTest.js
│ ├── 19-RestWithDestructuringTest.js
│ ├── 2-TemplateStringsMultilineTest.js
│ ├── 20-SpreadWithArraysTest.js
│ ├── 21-SpreadWithStringsTest.js
│ ├── 22-ClassCreationTest.js
│ ├── 23-ClassAccessorsTest.js
│ ├── 24-ClassStaticKeywordTest.js
│ ├── 25-ClassExtendsTest.js
│ ├── 26-ClassMoreExtendsTest.js
│ ├── 27-ClassSuperInsideAMethodTest.js
│ ├── 28-ClassSuperInConstructorTest.js
│ ├── 29-ArrayFromTest.js
│ ├── 3-TemplateStringsTaggedTest.js
│ ├── 30-ArrayOfStaticMethodTest.js
│ ├── 31-ArrayFillTest.js
│ ├── 32-ArrayFindTest.js
│ ├── 33-ArrayFindIndexTest.js
│ ├── 34-SymbolTest.js
│ ├── 35-SymbolForTest.js
│ ├── 36-KeyForTest.js
│ ├── 37-IteratorIterableArrayTest.js
│ ├── 38-IteratorIterableStringTest.js
│ ├── 39-IteratorCustomTest.js
│ ├── 4-TemplateStringsRawStringTest.js
│ ├── 40-IteratorExampleUsageTest.js
│ ├── 41-ArrayEntriesTest.js
│ ├── 42-ArrayKeysTest.js
│ ├── 44-MapBasicsTest.js
│ ├── 45-MapGetTest.js
│ ├── 46-MapSetTest.js
│ ├── 47-SetBasicsTest.js
│ ├── 48-SetAddTest.js
│ ├── 5-ArrowFunctionsBasicTest.js
│ ├── 53-MapInitializeTest.js
│ ├── 54-ObjectIsTest.js
│ ├── 55-NumberIsIntegerTest.js
│ ├── 57-DefaultParametersTest.js
│ ├── 58-ReflectBasicsTest.js
│ ├── 59-ReflectApplyTest.js
│ ├── 6-ArrowFunctionsBindingTest.js
│ ├── 60-ReflectGetPrototypeOfTest.js
│ ├── 61-ModulesImportTest.js
│ ├── 62-MapHasTest.js
│ ├── 63-StringIncludesTest.js
│ ├── 64-SetDeleteTest.js
│ ├── 65-SetApiOverviewTest.js
│ ├── 66-ObjectLiteralGetterTest.js
│ ├── 67-ObjectLiteralTest.js
│ ├── 68-ReflectConstructTest.js
│ ├── 69-ReflectDefinePropertyTest.js
│ ├── 7-BlockScopeLetTest.js
│ ├── 70-SetClearTest.js
│ ├── 71-StringRepeatTest.js
│ ├── 72-StringStrtsWithTest.js
│ ├── 74-StringEndsWithTest.js
│ ├── 76-PromiseCreationTest.js
│ ├── 77-PromiseChainingTest.js
│ ├── 78-PromiseApiOverviewTest.js
│ ├── 79-PromiseCatchTest.js
│ ├── 8-BlockScopeConstTest.js
│ └── 9-ObjectLiteralsBasicsTest.js
├── fibonacci
│ └── fibonacci.spec.js
├── find-the-right-triangle
│ └── find-the-right-triangle.spec.js
├── fizz-buzz
│ └── fizz-buzz.spec.js
├── greeting
│ └── greeting.spec.js
├── maxibon
│ ├── developer.spec.js
│ └── karumiHQs.spec.js
├── potter
│ └── potter.spec.js
├── prime-factors
│ └── prime-factors.spec.js
├── rock-paper-scissors
│ └── rock-paper-scissors.spec.js
├── roman-numerals
│ └── roman-numerals.spec.js
└── string-calculator
│ └── stringCalculator.spec.js
├── webpack.config.js
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["env"]
3 | }
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "es6": true,
4 | "browser": true,
5 | "node": true,
6 | "mocha": true
7 | },
8 | "rules": {
9 | "prettier/prettier": "error"
10 | },
11 | "plugins": [
12 | "prettier"
13 | ],
14 | "parserOptions": {
15 | "ecmaVersion": 6,
16 | "sourceType": "module",
17 | "ecmaFeatures": {
18 | "jsx": true
19 | }
20 | },
21 | "extends": [
22 | "eslint:recommended",
23 | "prettier",
24 | "plugin:import/errors",
25 | "plugin:import/warnings"
26 | ],
27 | "globals": {
28 | "assert": true,
29 | "expect": true,
30 | "jsc": true
31 | }
32 |
33 | }
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [pedrovgs]
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | # Distribution
61 | /dist
62 |
63 | # Visual Studio Code
64 | .vscode
65 |
66 | # IntelliJ
67 | .idea
68 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | cache:
2 | yarn: true
3 |
4 | before_install:
5 | - yarn --version
6 |
7 | script:
8 | - yarn install
9 | - yarn eslint src
10 | - yarn eslint test
11 | - yarn test
12 | - yarn webpack
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 | {one line to give the program's name and a brief idea of what it does.}
635 | Copyright (C) {year} {name of author}
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | {project} Copyright (C) {year} {fullname}
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JavaScriptKatas [](https://travis-ci.org/pedrovgs/JavaScriptKatas)
2 |
3 |
4 |
5 | JavaScript training repository used to practice and learn by solving some common katas.
6 |
7 | ### List of katas:
8 |
9 | * [ES6 Katas.](http://es6katas.org/)
10 | * [FizzBuzz.](http://codingdojo.org/KataFizzBuzz/)
11 | * [String calculator.](http://osherove.com/tdd-kata-1/)
12 | * [Find the right triangle.](https://gist.github.com/pedrovgs/32189838165fbe5c9e773ede534b97f4)
13 | * [Rock paper scissors.](http://agilekatas.co.uk/katas/RockPaperScissors-Kata)
14 | * [Bingo.](http://agilekatas.co.uk/katas/Bingo-Kata)
15 | * [Potter.](http://codingdojo.org/kata/Potter/)
16 | * [Roman numerals.](http://codingdojo.org/kata/RomanNumerals/)
17 | * [Prime factors.](https://www.rubyplus.com/articles/511-TDD-Beyond-Basics-Prime-Factors-Kata)
18 | * [Fibonacci.](https://medium.com/@chmeese/fibonacci-kata-93773b30dbb2#.3opu63eoj)
19 | * [Maxibon.](https://github.com/Karumi/MaxibonKataKotlin)
20 | * [Greeting.](https://github.com/testdouble/contributing-tests/wiki/Greeting-Kata)
21 |
22 | ### Executing tests:
23 |
24 | This project contains some tests written using [Mocha](https://mochajs.org/). You can easily run the tests by executing any of the following commands:
25 |
26 | ```
27 | yarn test //Executes every test.
28 | yarn test -w //Waits for code changes and executes every test.
29 | yarn test -g "String calculator spec*" //Executes tests matching with the regex passed as param.
30 | ```
31 |
32 | If you are using IntelliJ IDEA, WebStorm or any other IDE to run your tests you'll need to configure the mocha execution options adding the following configuration:
33 |
34 | ```
35 | --recursive --require ./test/bootload.js --require babel-register
36 | ```
37 |
38 | This configuration is the same you can find in the project ``package.json`` configuration.
39 |
40 | ### Packaging:
41 |
42 | This project uses [webpack](https://webpack.js.org) and [babel](https://babeljs.io) in order to pack a simple ``bundle.js`` file, with all the repository code, fully backward compatible with some old JavaScript versions. If you want to pack all this code into a single file you can easily do it by just running:
43 |
44 | ```
45 | yarn webpack
46 | ```
47 |
48 | ### Linter:
49 |
50 | This repository uses [eslint](https://eslint.org/) in order to check if the js code written matches the checkstyle configured. You can check if everything is ok by executing ``yarn eslint src`` and automatically fix the issues by executing ``yarn eslint --fix src`` if needed.
51 |
52 | Developed By
53 | ------------
54 |
55 | * Pedro Vicente Gómez Sánchez -
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | License
65 | -------
66 |
67 | Copyright 2017 Pedro Vicente Gómez Sánchez
68 |
69 | Licensed under the GNU General Public License, Version 3 (the "License");
70 | you may not use this file except in compliance with the License.
71 | You may obtain a copy of the License at
72 |
73 | http://www.gnu.org/licenses/gpl-3.0.en.html
74 |
75 | Unless required by applicable law or agreed to in writing, software
76 | distributed under the License is distributed on an "AS IS" BASIS,
77 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
78 | See the License for the specific language governing permissions and
79 | limitations under the License.
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "javascript-katas",
3 | "version": "1.0.0",
4 | "description": "JavaScript training repository used to learn and practice by solving some common katas.",
5 | "main": "src/index.js",
6 | "repository": "git@github.com:pedrovgs/JavaScriptKatas.git",
7 | "author": "pedrovgs ",
8 | "license": "GPL-3.0",
9 | "private": false,
10 | "scripts": {
11 | "test": "mocha --recursive --require ./test/bootload.js --require babel-register"
12 | },
13 | "devDependencies": {
14 | "babel-core": "^6.26.0",
15 | "babel-loader": "^7.1.2",
16 | "babel-polyfill": "^6.26.0",
17 | "babel-preset-env": "^1.6.1",
18 | "chai": "^4.1.2",
19 | "eslint": "^4.10.0",
20 | "eslint-config-prettier": "^2.7.0",
21 | "eslint-plugin-import": "^2.8.0",
22 | "eslint-plugin-prettier": "^2.3.1",
23 | "jsverify": "^0.8.3",
24 | "mocha": "^4.0.1",
25 | "mocha-eslint": "^4.1.0",
26 | "prettier": "^1.7.4",
27 | "prettier-eslint-cli": "^4.4.0",
28 | "webpack": "^3.8.1"
29 | },
30 | "dependencies": {
31 | "enumify": "^1.0.4"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/bingo/bingo.js:
--------------------------------------------------------------------------------
1 | export const usBingoNumbers = [...Array(75).keys()].map(key => key + 1);
2 |
3 | export class Game {
4 | constructor(availableNumbers, calledNumbers) {
5 | this.availableNumbers = availableNumbers;
6 | this.calledNumbers = calledNumbers;
7 | }
8 | }
9 |
10 | export class Card {
11 | constructor(numbers) {
12 | this.numbers = numbers;
13 | }
14 | }
15 |
16 | export function callNumber(game) {
17 | const availableNumbers = game.availableNumbers;
18 | const numbersLeft = availableNumbers.length;
19 | const calledNumber = availableNumbers[generateRandomInt(0, numbersLeft - 1)];
20 | const updatedGame = Object.assign({}, game);
21 | updatedGame.availableNumbers = updatedGame.availableNumbers.filter(
22 | number => number !== calledNumber
23 | );
24 | updatedGame.calledNumbers.push(calledNumber);
25 | return [calledNumber, updatedGame];
26 | }
27 |
28 | export function generateGame() {
29 | return new Game(usBingoNumbers.slice(), []);
30 | }
31 |
32 | export function generateCard() {
33 | let cardPossibleNumbers = usBingoNumbers.slice();
34 | const cardNumbers = [];
35 | for (let i = 0; i < 24; i++) {
36 | const cardNumberIndex = generateRandomInt(0, cardPossibleNumbers.length);
37 | const cardNumber = cardPossibleNumbers[cardNumberIndex];
38 | cardPossibleNumbers = cardPossibleNumbers.filter(x => x !== cardNumber);
39 | cardNumbers.push(cardNumber);
40 | }
41 | return new Card(cardNumbers);
42 | }
43 |
44 | export function isWinnerCard(card, game) {
45 | return card.numbers.every(number => game.calledNumbers.includes(number));
46 | }
47 |
48 | function generateRandomInt(min, max) {
49 | return parseInt(Math.random() * (max - min) + min);
50 | }
51 |
--------------------------------------------------------------------------------
/src/fibonacci/fibonacci.js:
--------------------------------------------------------------------------------
1 | export function fibonacci(n) {
2 | if (n === 0) {
3 | return 0;
4 | } else if (n === 1) {
5 | return 1;
6 | } else {
7 | return fibonacci(n - 1) + fibonacci(n - 2);
8 | }
9 | }
10 |
11 | export function fibonacciTailRec(n) {
12 | return fibonacciTailRecInner(n, 1, 0);
13 | }
14 |
15 | function fibonacciTailRecInner(n, a, b) {
16 | if (n === 0) {
17 | return b;
18 | } else {
19 | return fibonacciTailRecInner(n - 1, a + b, a);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/find-the-rigth-triangle/find-the-right-triangle.js:
--------------------------------------------------------------------------------
1 | function findRightTriangles() {
2 | const triangles = [];
3 | for (let c = 1; c <= 10; c++) {
4 | for (let a = 1; a <= c; a++) {
5 | for (let b = 1; b <= a; b++) {
6 | if (isRightTriangle(a, b, c)) {
7 | triangles.push([a, b, c]);
8 | }
9 | }
10 | }
11 | }
12 | return triangles;
13 | }
14 |
15 | function isRightTriangle(a, b, c) {
16 | return Math.pow(a, 2) + Math.pow(b, 2) === Math.pow(c, 2) && a + b + c === 24;
17 | }
18 |
19 | export default findRightTriangles;
20 |
--------------------------------------------------------------------------------
/src/fizz-buzz/fizz-buzz.js:
--------------------------------------------------------------------------------
1 | function fizzBuzz(value) {
2 | const isMultipleOf3 = isMultipleOf(value, 3);
3 | const isMultipleOf5 = isMultipleOf(value, 5);
4 | if (isMultipleOf3 && isMultipleOf5) return "FizzBuzz";
5 | else if (isMultipleOf3) return "Fizz";
6 | else if (isMultipleOf5) return "Buzz";
7 | else return value.toString();
8 | }
9 |
10 | function isMultipleOf(x, y) {
11 | return x % y == 0;
12 | }
13 |
14 | export default fizzBuzz;
15 |
--------------------------------------------------------------------------------
/src/greeting/greeting.js:
--------------------------------------------------------------------------------
1 | export function greet(...names) {
2 | names = splitNamesIfNeeded(names);
3 | if (isYelling(names)) {
4 | return yellingGreet(names);
5 | } else {
6 | const regularNames = names.filter(name => !isYelling(name));
7 | const yellingNames = names.filter(name => isYelling(name));
8 | if (regularNames.length > 0 && yellingNames.length > 0) {
9 | return yellingAndRegularGreet(regularNames, yellingNames);
10 | } else {
11 | return regularGreet(names);
12 | }
13 | }
14 | }
15 |
16 | function splitNamesIfNeeded(names) {
17 | if (typeof names === void 0 || names.length === 0) {
18 | return names;
19 | }
20 | return names.map(name => splitName(name)).reduce(function(a, b) {
21 | return a.concat(b);
22 | });
23 | }
24 |
25 | function splitName(name) {
26 | if (isAQuote(name)) {
27 | name = name.split('"').join("");
28 | return [name];
29 | } else {
30 | return name.split(",");
31 | }
32 | }
33 |
34 | function isAQuote(name) {
35 | return name.match('"*"') !== null;
36 | }
37 |
38 | function yellingGreet(names) {
39 | return `HELLO ${names}!`;
40 | }
41 |
42 | function regularGreet(names) {
43 | return `Hello, ${joinNames(names)}.`;
44 | }
45 |
46 | function yellingAndRegularGreet(regularNames, yellingNames) {
47 | return `${regularGreet(regularNames)} AND ${yellingGreet(yellingNames)}`;
48 | }
49 |
50 | function isYelling(names) {
51 | const isDefined = typeof names !== void 0;
52 | const isAnArray = Array.isArray(names);
53 | if (isDefined && isAnArray && names.length > 0) {
54 | return names.every(name => name === `${name}`.toUpperCase());
55 | } else if (isDefined && !isAnArray) {
56 | return names === names.toUpperCase();
57 | } else {
58 | return false;
59 | }
60 | }
61 |
62 | function joinNames(names) {
63 | if (typeof names === "undefined" || names.length === 0) {
64 | return "my friend";
65 | } else if (names.length === 1) {
66 | return names;
67 | } else if (names.length === 2) {
68 | return names.join(" and ");
69 | } else {
70 | const firstNames = names.slice(0, names.length - 1).join(", ");
71 | return `${firstNames}, and ${names[names.length - 1]}`;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrovgs/JavaScriptKatas/767270642aec15a3f9adf5d9377e496631c9110e/src/index.js
--------------------------------------------------------------------------------
/src/maxibon/maxibon.js:
--------------------------------------------------------------------------------
1 | export class Developer {
2 | constructor(name, maxibonsToGrab) {
3 | this.name = name;
4 | this.maxibonsToGrab = Math.max(0, maxibonsToGrab);
5 | }
6 | }
7 |
8 | export const Pedro = new Developer("Pedro", 3);
9 | export const Fran = new Developer("Fran", 1);
10 | export const Davide = new Developer("Davide", 0);
11 | export const Sergio = new Developer("Sergio", 2);
12 | export const Jorge = new Developer("Jorge", 1);
13 |
14 | export class KarumiHQs {
15 | constructor(chat = new ConsoleChat()) {
16 | this.chat = chat;
17 | this.maxibonsLeft = 10;
18 | }
19 |
20 | openFridge(devs) {
21 | if (Array.isArray(devs)) {
22 | openFridge(devs, this);
23 | } else {
24 | openFridge([devs], this);
25 | }
26 | }
27 | }
28 |
29 | function openFridge(devs, office) {
30 | devs.forEach(dev => {
31 | office.maxibonsLeft = Math.max(0, office.maxibonsLeft - dev.maxibonsToGrab);
32 | if (office.maxibonsLeft <= 2) {
33 | office.maxibonsLeft += 10;
34 | office.chat.sendMessage(
35 | `Hi guys, I'm ${dev.name}. We need more maxibons!`
36 | );
37 | }
38 | });
39 | }
40 |
41 | class ConsoleChat {
42 | sendMessage(message) {
43 | console.log(message); // eslint-disable-line
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/potter/potter.js:
--------------------------------------------------------------------------------
1 | import { Enum } from "enumify";
2 |
3 | export class HarryPotterBook extends Enum {}
4 | HarryPotterBook.initEnum(["BOOK_1", "BOOK_2", "BOOK_3", "BOOK_4", "BOOK_5"]);
5 |
6 | export function calculatePrice(cart) {
7 | const booksGroupedByBookNumber = groupBooks(cart);
8 | return calculatePriceBasedOnTheNumberOfBooks(booksGroupedByBookNumber);
9 | }
10 |
11 | function groupBooks(cart) {
12 | const groupedBooks = new Map();
13 | cart.forEach(value => {
14 | if (groupedBooks.has(value)) {
15 | const currentValue = groupedBooks.get(value);
16 | groupedBooks.set(value, currentValue + 1);
17 | } else {
18 | groupedBooks.set(value, 1);
19 | }
20 | });
21 | return Array.of(...groupedBooks.values());
22 | }
23 |
24 | function calculatePriceBasedOnTheNumberOfBooks(books) {
25 | const oneBookPrice = 8.0;
26 | const numberOfDifferentBooks = books.filter(x => x > 0).length;
27 | if (numberOfDifferentBooks === 0) {
28 | return 0.0;
29 | } else if (numberOfDifferentBooks === 1) {
30 | return oneBookPrice * books[0];
31 | } else if (numberOfDifferentBooks === 2) {
32 | return (
33 | oneBookPrice * 2 * 0.95 +
34 | calculatePriceBasedOnTheNumberOfBooks(removeDiscountedBooks(books))
35 | );
36 | } else if (numberOfDifferentBooks === 3) {
37 | return (
38 | oneBookPrice * 3 * 0.9 +
39 | calculatePriceBasedOnTheNumberOfBooks(removeDiscountedBooks(books))
40 | );
41 | } else if (numberOfDifferentBooks === 4) {
42 | return (
43 | oneBookPrice * 4 * 0.8 +
44 | calculatePriceBasedOnTheNumberOfBooks(removeDiscountedBooks(books))
45 | );
46 | } else if (numberOfDifferentBooks === 5) {
47 | return (
48 | oneBookPrice * 5 * 0.75 +
49 | calculatePriceBasedOnTheNumberOfBooks(removeDiscountedBooks(books))
50 | );
51 | }
52 | }
53 |
54 | function removeDiscountedBooks(books) {
55 | return books.map(x => x - 1);
56 | }
57 |
--------------------------------------------------------------------------------
/src/prime-factors/prime-factors.js:
--------------------------------------------------------------------------------
1 | function primeFactors(n) {
2 | if (n <= 1) {
3 | return [];
4 | } else {
5 | const firstPrimeLowerThanN = firstPrimeLowerThan(n);
6 | if (firstPrimeLowerThanN) {
7 | return [firstPrimeLowerThanN, ...primeFactors(n / firstPrimeLowerThanN)];
8 | } else {
9 | return [n];
10 | }
11 | }
12 | }
13 |
14 | function firstPrimeLowerThan(n) {
15 | for (let i = 2; i < n; i++) {
16 | if (n % i === 0) {
17 | return i;
18 | }
19 | }
20 | }
21 |
22 | export default primeFactors;
23 |
--------------------------------------------------------------------------------
/src/rock-paper-scissors/rock-paper-scissors.js:
--------------------------------------------------------------------------------
1 | import { Enum } from "enumify";
2 |
3 | export class Gesture extends Enum {}
4 | Gesture.initEnum(["PAPER", "ROCK", "SCISSORS"]);
5 |
6 | export class Player {
7 | constructor(name, gesture) {
8 | this.name = name;
9 | this.gesture = gesture;
10 | }
11 | }
12 |
13 | export class Result extends Enum {}
14 | Result.initEnum(["PLAYER_1_WINS", "PLAYER_2_WINS", "DRAW"]);
15 |
16 | const player1WinsResults = [
17 | [Gesture.ROCK, Gesture.SCISSORS],
18 | [Gesture.SCISSORS, Gesture.PAPER],
19 | [Gesture.PAPER, Gesture.ROCK]
20 | ];
21 | const player2WinsResults = player1WinsResults.map(game =>
22 | game.slice().reverse()
23 | );
24 |
25 | export function whoWins(player1, player2) {
26 | const match = [player1.gesture, player2.gesture];
27 | if (winsPlayer1(match)) {
28 | return Result.PLAYER_1_WINS;
29 | } else if (winsPlayer2(match)) {
30 | return Result.PLAYER_2_WINS;
31 | } else {
32 | return Result.DRAW;
33 | }
34 | }
35 |
36 | function winsPlayer1(match) {
37 | return wins(player1WinsResults, match);
38 | }
39 |
40 | function winsPlayer2(match) {
41 | return wins(player2WinsResults, match);
42 | }
43 |
44 | function wins(winningGames, match) {
45 | return winningGames.some(possibleGame =>
46 | possibleGame.every((v, i) => v === match[i])
47 | );
48 | }
49 |
--------------------------------------------------------------------------------
/src/roman-numerals/roman-numerals.js:
--------------------------------------------------------------------------------
1 | import { Enum } from "enumify";
2 |
3 | export class RomanNumeral extends Enum {}
4 | RomanNumeral.initEnum([
5 | "I",
6 | "IV",
7 | "V",
8 | "IX",
9 | "X",
10 | "XL",
11 | "XLIV",
12 | "L",
13 | "XC",
14 | "C",
15 | "CD",
16 | "D",
17 | "CM",
18 | "M"
19 | ]);
20 |
21 | const romanValues = [
22 | [RomanNumeral.I, 1],
23 | [RomanNumeral.IV, 4],
24 | [RomanNumeral.V, 5],
25 | [RomanNumeral.IX, 9],
26 | [RomanNumeral.X, 10],
27 | [RomanNumeral.XL, 40],
28 | [RomanNumeral.XLIV, 44],
29 | [RomanNumeral.L, 50],
30 | [RomanNumeral.XC, 90],
31 | [RomanNumeral.C, 100],
32 | [RomanNumeral.CD, 400],
33 | [RomanNumeral.D, 500],
34 | [RomanNumeral.CM, 900],
35 | [RomanNumeral.M, 1000]
36 | ];
37 |
38 | export function toArabic(roman) {
39 | return toArabicInner(roman.toUpperCase(), 0);
40 | }
41 |
42 | export function toRoman(arabic) {
43 | return toRomanInner(arabic, "");
44 | }
45 |
46 | function toArabicInner(roman, acc) {
47 | if (roman.length === 0) {
48 | return acc;
49 | } else if (roman.length === 1) {
50 | return acc + extractRomanValue(roman);
51 | } else {
52 | const combinedRomanNumeral = roman.substring(0, 2);
53 | if (isRomanNumeral(combinedRomanNumeral)) {
54 | const updatedAcc = acc + extractRomanValue(combinedRomanNumeral);
55 | const restOfTheRomanNumber = roman.slice(2, roman.length);
56 | return toArabicInner(restOfTheRomanNumber, updatedAcc);
57 | } else {
58 | const updatedAcc = acc + extractRomanValue(roman.substring(0, 1));
59 | const restOfTheRomanNumber = roman.slice(1, roman.length);
60 | return toArabicInner(restOfTheRomanNumber, updatedAcc);
61 | }
62 | }
63 | }
64 |
65 | function toRomanInner(arabic, acc) {
66 | if (arabic === 0) {
67 | return acc;
68 | } else {
69 | const closerRoman = extractCloserRoman(arabic);
70 | const closerRomanValue = closerRoman[1];
71 | return toRomanInner(arabic - closerRomanValue, acc + closerRoman[0].name);
72 | }
73 | }
74 |
75 | function extractCloserRoman(arabic) {
76 | let possibleValues = romanValues.filter(x => arabic - x[1] >= 0);
77 | return possibleValues[possibleValues.length - 1];
78 | }
79 |
80 | function isRomanNumeral(romanNumeral) {
81 | return typeof RomanNumeral.enumValueOf(romanNumeral) !== "undefined";
82 | }
83 |
84 | function extractRomanValue(romanNumber) {
85 | return romanValues.find(
86 | v => v[0] === RomanNumeral.enumValueOf(romanNumber)
87 | )[1];
88 | }
89 |
--------------------------------------------------------------------------------
/src/string-calculator/string-calculator.js:
--------------------------------------------------------------------------------
1 | function add(value) {
2 | if (containsCustomDelimiter(value)) {
3 | const customDelimiter = extractCustomDelimiter(value);
4 | return addWithDelimiters(removeCustomDelimiter(value, customDelimiter), [
5 | customDelimiter
6 | ]);
7 | } else {
8 | return addWithDelimiters(value, [",", "\n"]);
9 | }
10 | }
11 |
12 | function containsCustomDelimiter(value) {
13 | return value.startsWith("//");
14 | }
15 |
16 | function extractCustomDelimiter(value) {
17 | return value.split("//")[1][0];
18 | }
19 |
20 | function removeCustomDelimiter(value, delimiter) {
21 | const startIndex = value.indexOf(delimiter);
22 | return value.substring(startIndex + 1, value.length);
23 | }
24 |
25 | function addWithDelimiters(value, delimiters) {
26 | if (!value) {
27 | return 0;
28 | }
29 | const fixedDelimiter = " ";
30 | const sum = unifyDelimiters(value, fixedDelimiter, delimiters)
31 | .split(fixedDelimiter)
32 | .map(value => parseInt(value))
33 | .filter(value => Number.isInteger(value))
34 | .reduce((acc, value) => parseInt(acc) + parseInt(value));
35 | return parseInt(sum);
36 | }
37 |
38 | function unifyDelimiters(value, fixedDelimiter, delimiters) {
39 | let unifiedDelimitersValue = value;
40 | delimiters.forEach(d => {
41 | unifiedDelimitersValue = unifiedDelimitersValue
42 | .split(d)
43 | .join(fixedDelimiter);
44 | });
45 | return unifiedDelimitersValue;
46 | }
47 |
48 | export default add;
49 |
--------------------------------------------------------------------------------
/test/bingo/bingo.spec.js:
--------------------------------------------------------------------------------
1 | import {
2 | Card,
3 | Game,
4 | callNumber,
5 | generateGame,
6 | generateCard,
7 | usBingoNumbers,
8 | isWinnerCard
9 | } from "../../src/bingo/bingo.js";
10 |
11 | describe("Bingo spec", () => {
12 | jsc.property(
13 | "should return a called number between 1 and 75",
14 | arbitraryNumberOfCallNumberInvokations(),
15 | numberOfInvokations => {
16 | const game = generateGame();
17 |
18 | const executions = [...Array(numberOfInvokations).keys()].map(() => {
19 | const [calledNumber] = callNumber(game);
20 | return calledNumber >= 1 && calledNumber <= 75;
21 | });
22 | return executions.every(execution => execution === true);
23 | }
24 | );
25 |
26 | jsc.property(
27 | "should return a an updated game with the called number as part of the calledNumbers list and not as part of the available numbers",
28 | arbitraryNumberOfCallNumberInvokations(),
29 | numberOfInvokations => {
30 | let game = generateGame();
31 |
32 | const calledNumbers = [...Array(numberOfInvokations).keys()].map(() => {
33 | const result = callNumber(game);
34 | game = result[1];
35 | return result[0];
36 | });
37 |
38 | const numbersAreCalled = calledNumbers.every(calledNumber =>
39 | game.calledNumbers.includes(calledNumber)
40 | );
41 | const numbersAreNotAvailable = calledNumbers.every(
42 | calledNumber => !game.availableNumbers.includes(calledNumber)
43 | );
44 | return numbersAreCalled && numbersAreNotAvailable;
45 | }
46 | );
47 |
48 | jsc.property(
49 | "should generate cards with 24 values between 1 and 75",
50 | arbitraryNumberOfGenerateCardInvokations(),
51 | numberOfInvokations => {
52 | const cards = [...Array(numberOfInvokations).keys()].map(() =>
53 | generateCard()
54 | );
55 | return cards.every(
56 | card =>
57 | card.numbers.length == 24 &&
58 | card.numbers.every(number => number >= 1 && number <= 75)
59 | );
60 | }
61 | );
62 |
63 | jsc.property(
64 | "when cards are generated does not contain repeated values",
65 | arbitraryNumberOfGenerateCardInvokations(),
66 | numberOfInvokations => {
67 | const cards = [...Array(numberOfInvokations).keys()].map(() =>
68 | generateCard()
69 | );
70 | return cards.every(card =>
71 | card.numbers.every(number =>
72 | card.numbers.filter(x => (x === number.length) === 1)
73 | )
74 | );
75 | }
76 | );
77 |
78 | jsc.property(
79 | "a card is the winner if its 24 numbers have bein called",
80 | arbitraryGame(),
81 | game => {
82 | const winnerCard = new Card(game.calledNumbers);
83 | return isWinnerCard(winnerCard, game);
84 | }
85 | );
86 |
87 | it("any card will be the winner if the game calls 75 numbers", () => {
88 | let game = generateGame();
89 | const card = generateCard();
90 |
91 | for (let i = 0; i < 75; i++) {
92 | game = callNumber(game)[1];
93 | }
94 |
95 | expect(isWinnerCard(card, game)).to.equal(true);
96 | });
97 |
98 | it("won't be winner cards if just 23 numbers are called", () => {
99 | let game = generateGame();
100 | const card = generateCard();
101 |
102 | for (let i = 0; i < 23; i++) {
103 | game = callNumber(game)[1];
104 | }
105 |
106 | expect(isWinnerCard(card, game)).to.equal(false);
107 | });
108 |
109 | function arbitraryGame(minNumberOfcalledNumbers = 24) {
110 | return jsc
111 | .integer(1, Math.min(minNumberOfcalledNumbers, 75))
112 | .smap(numberOfCalledNumbers =>
113 | generateGameWithCalledNumbers(numberOfCalledNumbers)
114 | );
115 | }
116 |
117 | function generateGameWithCalledNumbers(numberOfCalledNumbers) {
118 | let availableNumbers = usBingoNumbers.slice();
119 | const calledNumbers = [];
120 | for (let i = 0; i < numberOfCalledNumbers; i++) {
121 | const calledNumber =
122 | availableNumbers[generateRandomInt(0, availableNumbers.length - 1)];
123 | availableNumbers = availableNumbers.filter(x => x !== calledNumber);
124 | calledNumbers.push(calledNumber);
125 | }
126 | return new Game(availableNumbers, calledNumbers);
127 | }
128 |
129 | function arbitraryNumberOfCallNumberInvokations() {
130 | return jsc.integer(1, 75);
131 | }
132 |
133 | function arbitraryNumberOfGenerateCardInvokations() {
134 | return jsc.integer(1, 50);
135 | }
136 |
137 | function generateRandomInt(min, max) {
138 | return parseInt(Math.random() * (max - min) + min);
139 | }
140 | });
141 |
--------------------------------------------------------------------------------
/test/bootload.js:
--------------------------------------------------------------------------------
1 | global.assert = require("assert");
2 | global.expect = require("chai").expect;
3 | global.jsc = require("jsverify");
4 | const mocha = require("mocha");
5 | global.describe = mocha.describe;
6 | global.it = mocha.it;
7 |
--------------------------------------------------------------------------------
/test/es6katas/1-TemplateStringsTest.js:
--------------------------------------------------------------------------------
1 | // 1: template strings - basics
2 | // To do: make all tests pass, leave the asserts unchanged!
3 |
4 | describe("a template string, is wrapped in ` (backticks) instead of ' or \"", function() {
5 | describe("by default, behaves like a normal string", function() {
6 | it("just surrounded by backticks", function() {
7 | var str = `like a string`;
8 | assert.equal(str, "like a string");
9 | });
10 | });
11 |
12 | var x = 42;
13 | var y = 23;
14 |
15 | describe('can evaluate variables, which are wrapped in "${" and "}"', function() {
16 | it('e.g. a simple variable "${x}" just gets evaluated', function() {
17 | var evaluated = `x=${x}`;
18 | assert.equal(evaluated, "x=" + x);
19 | });
20 |
21 | it("multiple variables get evaluated too", function() {
22 | var evaluated = `${x}+${y}`;
23 | assert.equal(evaluated, x + "+" + y);
24 | });
25 | });
26 |
27 | describe('can evaluate any expression, wrapped inside "${...}"', function() {
28 | it('all inside "${...}" gets evaluated', function() {
29 | var evaluated = `${x + y}`;
30 | assert.equal(evaluated, x + y);
31 | });
32 |
33 | it('inside "${...}" can also be a function call', function() {
34 | function getDomain() {
35 | return "tddbin.com";
36 | }
37 | var evaluated = `${getDomain()}`;
38 | assert.equal(evaluated, "tddbin.com");
39 | });
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/test/es6katas/10-DestructuringArraysTest.js:
--------------------------------------------------------------------------------
1 | // 10: destructuring - array
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("destructuring arrays makes shorter code", () => {
5 | it("extract value from array, e.g. extract 0 into x like so `let [x] = [0];`", () => {
6 | let [firstValue] = [1];
7 | assert.strictEqual(firstValue, 1);
8 | });
9 |
10 | it("swap two variables, in one operation", () => {
11 | let [x, y] = ["ax", "why"];
12 | [x, y] = [y, x];
13 | assert.deepEqual([x, y], ["why", "ax"]);
14 | });
15 |
16 | it("leading commas", () => {
17 | const all = ["ax", "why", "zet"];
18 | const [, , z] = all;
19 | assert.equal(z, "zet");
20 | });
21 |
22 | it("extract from nested arrays", () => {
23 | const user = [["Some", "One"], 23];
24 | const [[firstName, surname], age] = user;
25 |
26 | const expected = "Some One = 23 years";
27 | assert.equal(`${firstName} ${surname} = ${age} years`, expected);
28 | });
29 |
30 | it("chained assignments", () => {
31 | let c, d;
32 | let [a, b] = ([c, d] = [1, 2]);
33 | assert.deepEqual([a, b, c, d], [1, 2, 1, 2]);
34 | });
35 |
36 | it("in for-of loop", () => {
37 | for (var [, a, b] of [[0, 1, 2]]) { // eslint-disable-line
38 | }
39 | assert.deepEqual([a, b], [1, 2]);
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/test/es6katas/11-DestructuringStringsTest.js:
--------------------------------------------------------------------------------
1 | // 11: destructuring - string
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("destructuring also works on strings", () => {
5 | it("destructure every character", () => {
6 | let [a, b, c] = "abc";
7 | assert.deepEqual([a, b, c], ["a", "b", "c"]);
8 | });
9 |
10 | it("missing characters are undefined", () => {
11 | const [a, b, c] = "ab"; // eslint-disable-line
12 | assert.equal(c, void 0);
13 | });
14 |
15 | it("unicode character work too", () => {
16 | const [space, coffee] = "a☕"; // eslint-disable-line
17 | assert.equal(coffee, "\u{2615}");
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/test/es6katas/12-DestructuringObjectsTest.js:
--------------------------------------------------------------------------------
1 | // 12: destructuring - object
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("destructuring objects", () => {
5 | it("is simple", () => {
6 | const { x } = { x: 1 };
7 | assert.equal(x, 1);
8 | });
9 |
10 | describe("nested", () => {
11 | it("multiple objects", () => {
12 | const magic = { first: 23, second: 42 };
13 | const { magic: { second } } = { magic };
14 | assert.equal(second, 42);
15 | });
16 | it("object and array", () => {
17 | const { z: [, x] } = { z: [23, 42] };
18 | assert.equal(x, 42);
19 | });
20 | it("array and object", () => {
21 | const [, [{ lang }]] = [null, [{ env: "browser", lang: "ES6" }]];
22 | assert.equal(lang, "ES6");
23 | });
24 | });
25 |
26 | describe("interesting", () => {
27 | it("missing refs become undefined", () => {
28 | const { z } = { x: 1, y: 2 };
29 | assert.equal(z, void 0);
30 | });
31 |
32 | it("destructure from builtins (string)", () => {
33 | const { substr } = "1";
34 | assert.equal(substr, String.prototype.substr);
35 | });
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/test/es6katas/13-DestructuringDefaults.js:
--------------------------------------------------------------------------------
1 | // 13: destructuring - defaults
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("destructuring can also have default values", () => {
5 | it("for an empty array", () => {
6 | const [a = 1] = [];
7 | assert.equal(a, 1);
8 | });
9 |
10 | it("for a missing value", () => {
11 | const [b = 2] = [undefined, 1, 3];
12 | assert.equal(b, 2);
13 | });
14 |
15 | it("in an object", () => {
16 | const { b = 2 } = { a: 1 };
17 | assert.equal(b, 2);
18 | });
19 |
20 | it("if the value is undefined", () => {
21 | const { b = 2 } = { a: 1, b: void 0 };
22 | assert.strictEqual(b, 2);
23 | });
24 |
25 | it("also a string works with defaults", () => {
26 | const [a, b = 2] = "1";
27 | assert.equal(a, "1");
28 | assert.equal(b, 2);
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/test/es6katas/14-DestructuringParametersTest.js:
--------------------------------------------------------------------------------
1 | // 14: destructuring - parameters
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("destructuring function parameters", () => {
5 | describe("destruct parameters", () => {
6 | it("multiple params from object", () => {
7 | const fn = ({ id, name }) => {
8 | assert.equal(id, 42);
9 | assert.equal(name, "Wolfram");
10 | };
11 | const user = { name: "Wolfram", id: 42 };
12 | fn(user);
13 | });
14 |
15 | it("multiple params from array/object", () => {
16 | const fn = ([, { name }]) => {
17 | assert.equal(name, "Alice");
18 | };
19 | const users = [{ name: "nobody" }, { name: "Alice", id: 42 }];
20 | fn(users);
21 | });
22 | });
23 |
24 | describe("default values", () => {
25 | it("for simple values", () => {
26 | const fn = (id, name = "Bob") => {
27 | assert.strictEqual(id, 23);
28 | assert.strictEqual(name, "Bob");
29 | };
30 | fn(23);
31 | });
32 |
33 | it("for a missing array value", () => {
34 | const defaultUser = { id: 23, name: "Joe" };
35 | const fn = ([user]) => {
36 | assert.deepEqual(user, defaultUser);
37 | };
38 | fn([defaultUser]);
39 | });
40 |
41 | it("mix of parameter types", () => {
42 | const fn = (id, [arr], { obj }) => {
43 | assert.equal(id, 1);
44 | assert.equal(arr, 2);
45 | assert.equal(obj, 3);
46 | };
47 | fn(1, [2], { obj: 3 });
48 | });
49 | });
50 | });
51 |
--------------------------------------------------------------------------------
/test/es6katas/15-DestructuringAssignTest.js:
--------------------------------------------------------------------------------
1 | // 15: destructuring - assign
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("assign object property values to new variables while destructuring", () => {
5 | describe("for simple objects", function() {
6 | it("use a colon after the property name, like so `propertyName: newName`", () => {
7 | const { x: y } = { x: 1 };
8 | assert.equal(y, 1);
9 | });
10 |
11 | it("assign a new name and give it a default value using `= `", () => {
12 | const { x: y = 42 } = { y: 23 };
13 | assert.equal(y, 42);
14 | });
15 | });
16 |
17 | describe("for function parameter names", function() {
18 | it("do it the same way, with a colon behind it", () => {
19 | const fn = ({ x: y }) => {
20 | assert.equal(y, 1);
21 | };
22 | fn({ x: 1 });
23 | });
24 |
25 | it("giving it a default value is possible too, like above", () => {
26 | const fn = ({ x: y = 3 }) => {
27 | assert.equal(y, 3);
28 | };
29 | fn({});
30 | });
31 | });
32 | });
33 |
--------------------------------------------------------------------------------
/test/es6katas/16-ObjectLiteralComputedPropertiesTest.js:
--------------------------------------------------------------------------------
1 | // 16: object-literal - computed properties
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("Object literal properties may be computed values", () => {
5 | it("a computed property `x` needs to be surrounded by `[]`", () => {
6 | const propertyName = "x";
7 | const obj = { [propertyName]: 1 };
8 | assert.equal(obj.x, 1);
9 | });
10 |
11 | it("can also get a function assigned", () => {
12 | const key = "func";
13 | const obj = { [key]: () => "seven" };
14 | assert.equal(obj.func(), "seven");
15 | });
16 |
17 | it("the key may also be the result of a function call", () => {
18 | const getName = () => "propertyName";
19 | const obj = {
20 | [getName()]() {
21 | return "seven";
22 | }
23 | };
24 | assert.equal(obj.propertyName(), "seven");
25 | });
26 |
27 | it("the key can also be constructed by an expression", () => {
28 | const what = "tyName";
29 | const obj = { ["proper" + what]: true };
30 | assert.equal("propertyName" in obj, true);
31 | });
32 |
33 | it("accessor keys can be computed names too", () => {
34 | const obj = {
35 | get ["key"]() {
36 | return 1;
37 | }
38 | };
39 | assert.equal(obj.key, 1);
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/test/es6katas/17-UnicodeInStringsTest.js:
--------------------------------------------------------------------------------
1 | // 17: unicode - in strings
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("unicode strings", () => {
5 | it("are \\u prefixed", () => {
6 | const nuclear = "\u2622";
7 | assert.equal(nuclear, "☢");
8 | });
9 |
10 | it("value is 4 bytes/digits", () => {
11 | const nuclear = "\u2622";
12 | assert.equal(`no more ${nuclear}`, "no more ☢");
13 | });
14 |
15 | it("value is hexadecimal", () => {
16 | const nuclear = `\u006E\u006F more \u2622`;
17 | assert.equal(nuclear, "no more ☢");
18 | });
19 |
20 | it("curly braces may surround the value", () => {
21 | const nuclear = `\u{0000000006E}\u{00006F} more \u2622`;
22 | assert.equal(nuclear, "no more ☢");
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/test/es6katas/18-RestAsParameterTest.js:
--------------------------------------------------------------------------------
1 | // 18: rest - as-parameter
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("rest in function params", () => {
5 | it("must be the last parameter", () => {
6 | const fn = (veryLast, ...rest) => {
7 | assert.deepEqual([1, 2], rest);
8 | };
9 | fn(0, 1, 2);
10 | });
11 |
12 | it("can be used to get all other parameters", () => {
13 | const fn = (firstParam, secondParam, rest) => {
14 | assert.deepEqual([3, 4], rest);
15 | };
16 | fn(1, 2, [3, 4]);
17 | });
18 |
19 | it("makes `arguments` obsolete", () => {
20 | const fn = (...args) => {
21 | assert.deepEqual([42, "twenty three", "win"], args);
22 | };
23 | fn(42, "twenty three", "win");
24 | });
25 |
26 | it("eliminate `arguments`!!!", () => {
27 | const fn = (...args) => args;
28 | const [, ...rest] = fn(1, 2, 3);
29 | assert.deepEqual([2, 3], rest);
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/test/es6katas/19-RestWithDestructuringTest.js:
--------------------------------------------------------------------------------
1 | // 19: rest - with-destructuring
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("rest with destructuring", () => {
5 | it("rest parameter must be last", () => {
6 | const [...all] = [1, 2, 3, 4];
7 | assert.deepEqual(all, [1, 2, 3, 4]);
8 | });
9 |
10 | it("assign rest of an array to a variable", () => {
11 | const [, ...all] = [1, 2, 3, 4];
12 | assert.deepEqual(all, [2, 3, 4]);
13 | });
14 |
15 | // the following are actually using `spread` ... oops, to be fixed
16 | it("concat differently", () => {
17 | const theEnd = [3, 4];
18 | const allInOne = [1, 2, ...[...theEnd]];
19 | assert.deepEqual(allInOne, [1, 2, 3, 4]);
20 | });
21 |
22 | it("`apply` made simple, even for constructors", () => {
23 | const theDate = [2015, 1, 1];
24 | const date = new Date(...theDate);
25 | assert.deepEqual(new Date(2015, 1, 1), date);
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/test/es6katas/2-TemplateStringsMultilineTest.js:
--------------------------------------------------------------------------------
1 | // 2: template strings - multiline
2 | // To do: make all tests pass, leave the asserts unchanged!
3 |
4 | describe("template string, can contain multiline content", function() {
5 | it("a normal string can`t span across multiple lines", function() {
6 | var normalString = `line1\nline2`;
7 | assert.equal(normalString, "line1\nline2");
8 | });
9 |
10 | it("wrapped in backticks it can span over multiple lines", function() {
11 | var templateString = `line1
12 | line2`;
13 | assert.equal(templateString, "line1\nline2");
14 | });
15 |
16 | it("even over more than two lines", function() {
17 | var multiline = `line 1
18 | line 2
19 | line 3
20 | line 4`;
21 | assert.equal(multiline.split("\n").length, 4);
22 | });
23 |
24 | describe("and expressions inside work too", function() {
25 | var x = 42;
26 |
27 | it("like simple variables", function() {
28 | var multiline = `line 1
29 | ${x}`;
30 | assert.equal(multiline, "line 1\n 42");
31 | });
32 |
33 | it("also here spaces matter", function() {
34 | var multiline = `
35 | ${x}`;
36 | assert.equal(multiline, "\n42");
37 | });
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/test/es6katas/20-SpreadWithArraysTest.js:
--------------------------------------------------------------------------------
1 | // 20: spread - with-arrays
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("spread with arrays", () => {
5 | it("extracts each array item", function() {
6 | const [a, b] = [...[1, 2]];
7 | assert.equal(a, 1);
8 | assert.equal(b, 2);
9 | });
10 |
11 | it("in combination with rest", function() {
12 | const [a, b, ...rest] = [...[1, 2, 3, 4, 5]];
13 | assert.equal(a, 1);
14 | assert.equal(b, 2);
15 | assert.deepEqual(rest, [3, 4, 5]);
16 | });
17 |
18 | it("spreading into the rest", function() {
19 | const [, ...rest] = [...[, 1, 2, 3, 4, 5]]; // eslint-disable-line
20 | assert.deepEqual(rest, [1, 2, 3, 4, 5]);
21 | });
22 |
23 | describe("used as function parameter", () => {
24 | it("prefix with `...` to spread as function params", function() {
25 | const magicNumbers = [1, 2];
26 | const fn = (magicA, magicB) => {
27 | assert.deepEqual(magicNumbers[0], magicA);
28 | assert.deepEqual(magicNumbers[1], magicB);
29 | };
30 | fn(...magicNumbers);
31 | });
32 |
33 | it("pass an array of numbers to Math.max()", function() {
34 | const max = Math.max(...[23, 0, 42, 41]);
35 | assert.equal(max, 42);
36 | });
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/test/es6katas/21-SpreadWithStringsTest.js:
--------------------------------------------------------------------------------
1 | // 21: spread - with-strings
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("spread with strings", () => {
5 | it("simply spread each char of a string", function() {
6 | const [a, b] = [..."ab"];
7 | assert.equal(a, "a");
8 | assert.equal(b, "b");
9 | });
10 |
11 | it("extracts each array item", function() {
12 | const [, a, b] = ["a", ..."12"];
13 | assert.equal(a, 1);
14 | assert.equal(b, 2);
15 | });
16 |
17 | it("works anywhere inside an array (must not be last)", function() {
18 | const letters = ["a", ..."bcd", "e", "f"];
19 | assert.equal(letters.length, 6);
20 | });
21 |
22 | it("dont confuse with the rest operator", function() {
23 | const [...rest] = [..."1234", ..."5"];
24 | assert.deepEqual(rest, [1, 2, 3, 4, 5]);
25 | });
26 |
27 | it("passed as function parameter", function() {
28 | const max = Math.max(..."12345");
29 | assert.deepEqual(max, 5);
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/test/es6katas/22-ClassCreationTest.js:
--------------------------------------------------------------------------------
1 | // 22: class - creation
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("class creation", () => {
5 | it("is as simple as `class XXX {}`", function() {
6 | class TestClass {}
7 |
8 | const instance = new TestClass();
9 | assert.equal(typeof instance, "object");
10 | });
11 |
12 | it("class is block scoped", () => {
13 | {
14 | class Inside {} // eslint-disable-line
15 | {
16 | class Inside {} // eslint-disable-line
17 | }
18 | }
19 | assert.equal(typeof Inside, "undefined");
20 | });
21 |
22 | it("special method is `constructor`", function() {
23 | class User {
24 | constructor(id) {
25 | this.id = id;
26 | }
27 | }
28 |
29 | const user = new User(42);
30 | assert.equal(user.id, 42);
31 | });
32 |
33 | it("defining a method is simple", function() {
34 | class User {
35 | writesTests() {
36 | return false;
37 | }
38 | }
39 |
40 | const notATester = new User();
41 | assert.equal(notATester.writesTests(), false);
42 | });
43 |
44 | it("multiple methods need no commas (opposed to object notation)", function() {
45 | class User {
46 | wroteATest() {
47 | this.everWroteATest = true;
48 | }
49 | isLazy() {
50 | return !this.everWroteATest;
51 | }
52 | }
53 |
54 | const tester = new User();
55 | assert.equal(tester.isLazy(), true);
56 | tester.wroteATest();
57 | assert.equal(tester.isLazy(), false);
58 | });
59 |
60 | it("anonymous class", () => {
61 | const classType = typeof function() {};
62 | assert.equal(classType, "function");
63 | });
64 | });
65 |
--------------------------------------------------------------------------------
/test/es6katas/23-ClassAccessorsTest.js:
--------------------------------------------------------------------------------
1 | // 23: class - accessors
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("class accessors (getter and setter)", () => {
5 | it("only a getter is defined like a method prefixed with `get`", () => {
6 | class MyAccount {
7 | get balance() {
8 | return Infinity;
9 | }
10 | }
11 |
12 | assert.equal(new MyAccount().balance, Infinity);
13 | });
14 |
15 | it("a setter has the prefix `set`", () => {
16 | class MyAccount {
17 | get balance() {
18 | return this.amount;
19 | }
20 | set balance(amount) {
21 | this.amount = amount;
22 | }
23 | }
24 |
25 | const account = new MyAccount();
26 | account.balance = 23;
27 | assert.equal(account.balance, 23);
28 | });
29 |
30 | describe("dynamic accessors", () => {
31 | it("a dynamic getter name is enclosed in [ and ]", function() {
32 | const balance = "yourMoney";
33 | class YourAccount {
34 | get [balance]() {
35 | return -Infinity;
36 | }
37 | }
38 |
39 | assert.equal(new YourAccount().yourMoney, -Infinity);
40 | });
41 |
42 | it("a dynamic setter name as well", function() {
43 | const propertyName = "balance";
44 | class MyAccount {
45 | get [propertyName]() {
46 | return this.amount;
47 | }
48 | set [propertyName](amount) {
49 | this.amount = 23;
50 | }
51 | }
52 |
53 | const account = new MyAccount();
54 | account.balance = 42;
55 | assert.equal(account.balance, 23);
56 | });
57 | });
58 | });
59 |
--------------------------------------------------------------------------------
/test/es6katas/24-ClassStaticKeywordTest.js:
--------------------------------------------------------------------------------
1 | // 24: class - static keyword
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("inside a class you can use the `static` keyword", () => {
5 | describe("for methods", () => {
6 | class IntegrationTest {} // eslint-disable-line
7 | class UnitTest {}
8 |
9 | it("a static method just has the prefix `static`", () => {
10 | class TestFactory {
11 | static makeTest() {
12 | return new UnitTest();
13 | }
14 | }
15 |
16 | assert.ok(TestFactory.makeTest() instanceof UnitTest);
17 | });
18 |
19 | it("the method name can be dynamic/computed at runtime", () => {
20 | const methodName = "createTest";
21 | class TestFactory {
22 | static [methodName]() {
23 | return new UnitTest();
24 | }
25 | }
26 |
27 | assert.ok(TestFactory.createTest() instanceof UnitTest);
28 | });
29 | });
30 |
31 | describe("for accessors", () => {
32 | it("a getter name can be static, just prefix it with `static`", () => {
33 | class UnitTest {
34 | static get testType() {
35 | return "unit";
36 | }
37 | }
38 |
39 | assert.equal(UnitTest.testType, "unit");
40 | });
41 |
42 | it("even a static getter name can be dynamic/computed at runtime", () => {
43 | const type = "test" + "Type";
44 | class IntegrationTest {
45 | static get [type]() {
46 | return "integration";
47 | }
48 | }
49 |
50 | assert.ok("testType" in IntegrationTest);
51 | assert.equal(IntegrationTest.testType, "integration");
52 | });
53 | });
54 | });
55 |
--------------------------------------------------------------------------------
/test/es6katas/25-ClassExtendsTest.js:
--------------------------------------------------------------------------------
1 | // 25: class - extends
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("classes can inherit from another", () => {
5 | describe("the default super class is Object", () => {
6 | it("class A is an instance of Object", () => {
7 | class A {}
8 |
9 | assert.equal(new A() instanceof Object, true);
10 | });
11 |
12 | it("B extends A, B is also instance of Object", () => {
13 | class A {}
14 | class B extends A {}
15 |
16 | assert.equal(new B() instanceof A, true);
17 | assert.equal(new B() instanceof Object, true);
18 | });
19 | });
20 |
21 | describe("instance of", () => {
22 | it("when B inherits from A, `new B()` is also an instance of A", () => {
23 | class A {}
24 | class B extends A {}
25 |
26 | assert.equal(new B() instanceof A, true);
27 | });
28 |
29 | it("extend over multiple levels", () => {
30 | class A {}
31 | class B extends A {}
32 | class C extends B {}
33 |
34 | let instance = new C();
35 | assert.equal(instance instanceof A, true);
36 | });
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/test/es6katas/26-ClassMoreExtendsTest.js:
--------------------------------------------------------------------------------
1 | // 26: class - more-extends
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("class can inherit from another", () => {
5 | it('extend an `old style` "class", a function, still works', () => {
6 | class A {}
7 | class B extends A {}
8 |
9 | assert.equal(new B() instanceof A, true);
10 | });
11 |
12 | describe("prototypes are as you know them", () => {
13 | class A {}
14 | class B extends A {}
15 | it("A is the prototype of B", () => {
16 | const isIt = A.isPrototypeOf(B);
17 | assert.equal(isIt, true);
18 | });
19 | it("A`s prototype is also B`s prototype", () => {
20 | const proto = B.prototype;
21 | // Remember: don't touch the assert!!! :)
22 | assert.equal(A.prototype.isPrototypeOf(proto), true);
23 | });
24 | });
25 |
26 | describe("`extends` using an expression", () => {
27 | it("eg the inline assignment of the parent class", () => {
28 | let A;
29 | class B extends (A = class {}) {}
30 |
31 | assert.equal(new B() instanceof A, true);
32 | });
33 |
34 | it("or calling a function that returns the parent class", () => {
35 | const returnParent = beNull => (beNull ? null : class {});
36 | class B extends returnParent(true) {}
37 |
38 | assert.equal(Object.getPrototypeOf(B.prototype), null);
39 | });
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/test/es6katas/27-ClassSuperInsideAMethodTest.js:
--------------------------------------------------------------------------------
1 | // 27: class - super inside a method
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("inside a class use `super` to access parent methods", () => {
5 | it("use of `super` without `extends` fails (already when transpiling)", () => {
6 | class A {
7 | hasSuper() {
8 | return false;
9 | }
10 | }
11 |
12 | assert.equal(new A().hasSuper(), false);
13 | });
14 |
15 | it("`super` with `extends` calls the method of the given name of the parent class", () => {
16 | class A {
17 | hasSuper() {
18 | return true;
19 | }
20 | }
21 | class B extends A {
22 | hasSuper() {
23 | return super.hasSuper();
24 | }
25 | }
26 |
27 | assert.equal(new B().hasSuper(), true);
28 | });
29 |
30 | it("when overridden a method does NOT automatically call its super method", () => {
31 | class A {
32 | hasSuper() {
33 | return true;
34 | }
35 | }
36 | class B extends A {
37 | hasSuper() {
38 | return undefined;
39 | }
40 | }
41 |
42 | assert.equal(new B().hasSuper(), void 0);
43 | });
44 |
45 | it("`super` works across any number of levels of inheritance", () => {
46 | class A {
47 | iAmSuper() {
48 | return this.youAreSuper;
49 | }
50 | }
51 | class B extends A {
52 | constructor() {
53 | super();
54 | this.youAreSuper = true;
55 | }
56 | }
57 | class C extends B {
58 | iAmSuper() {
59 | return super.iAmSuper();
60 | }
61 | }
62 |
63 | assert.equal(new C().iAmSuper(), true);
64 | });
65 |
66 | it("accessing an undefined member of the parent class returns `undefined`", () => {
67 | class A {}
68 | class B extends A {
69 | getMethod() {
70 | return super.attribute;
71 | }
72 | }
73 |
74 | assert.equal(new B().getMethod(), void 0);
75 | });
76 | });
77 |
--------------------------------------------------------------------------------
/test/es6katas/28-ClassSuperInConstructorTest.js:
--------------------------------------------------------------------------------
1 | // 28: class - super in constructor
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("class", () => {
5 | it("if you `extend` a class, use `super()` to call the parent constructor", () => {
6 | class A {
7 | constructor() {
8 | this.levels = 1;
9 | }
10 | }
11 | class B extends A {
12 | constructor() {
13 | super();
14 | this.levels++;
15 | }
16 | }
17 |
18 | assert.equal(new B().levels, 2);
19 | });
20 |
21 | it("`super()` may also take params", () => {
22 | class A {
23 | constructor(startValue = 1, addTo = 1) {
24 | this.counter = startValue + addTo;
25 | }
26 | }
27 | class B extends A {
28 | constructor(...args) {
29 | super(...args);
30 | this.counter++;
31 | }
32 | }
33 |
34 | assert.equal(new B(42, 2).counter, 45);
35 | });
36 |
37 | it("it is important where you place your `super()` call!", () => {
38 | class A {
39 | inc() {
40 | this.countUp = 1;
41 | }
42 | }
43 | class B extends A {
44 | inc() {
45 | this.countUp = 2;
46 | super.inc();
47 | return this.countUp;
48 | }
49 | }
50 |
51 | assert.equal(new B().inc(), 1);
52 | });
53 | });
54 |
--------------------------------------------------------------------------------
/test/es6katas/29-ArrayFromTest.js:
--------------------------------------------------------------------------------
1 | // 29: array - `Array.from` static method
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Array.from` converts an array-like object or list into an Array", () => {
5 | const arrayLike = { 0: "one", 1: "two", length: 2 };
6 |
7 | it("call `Array.from` with an array-like object", function() {
8 | const arr = Array.from(arrayLike);
9 |
10 | assert.deepEqual(arr, ["one", "two"]);
11 | });
12 |
13 | describe("custom conversion using a map function as second param", () => {
14 | it("we can modify the value before putting it in the array", function() {
15 | const arr = Array.from(arrayLike, value => value.toUpperCase());
16 | assert.deepEqual(arr, ["ONE", "TWO"]);
17 | });
18 |
19 | it("and we also get the object`s key as second parameter", function() {
20 | const arr = Array.from(arrayLike, (key, value) => `${value}=${key}`);
21 | assert.deepEqual(arr, ["0=one", "1=two"]);
22 | });
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/test/es6katas/3-TemplateStringsTaggedTest.js:
--------------------------------------------------------------------------------
1 | // 3: template strings - tagged
2 | // To do: make all tests pass, leave the asserts unchanged!
3 |
4 | describe("tagged template strings, are an advanced form of template strings", function() {
5 | it('syntax: prefix the template string with a function to call (without "()" around it)', function() {
6 | function tagFunction(s) {
7 | return s;
8 | }
9 | var evaluated = tagFunction`template string`;
10 | assert.equal(evaluated, "template string");
11 | });
12 |
13 | describe("the function can access each part of the template", function() {
14 | describe("the 1st parameter - receives only the pure strings of the template string", function() {
15 | function tagFunction(strings) {
16 | return strings;
17 | }
18 |
19 | it("the strings are an array", function() {
20 | var result = tagFunction`template string`;
21 | assert.deepEqual(tagFunction`template string`, result);
22 | });
23 |
24 | it("expressions are NOT passed to it", function() {
25 | var tagged = tagFunction`one${23}two`;
26 | assert.deepEqual(tagged, ["one", "two"]);
27 | });
28 | });
29 |
30 | describe("the 2nd and following parameters - contain the values of the processed substitution", function() {
31 | var one = 1;
32 | var two = 2;
33 | var three = 3;
34 | it("the 2nd parameter contains the first expression`s value", function() {
35 | function firstValueOnly(strings, firstValue) {
36 | return firstValue;
37 | }
38 | assert.equal(firstValueOnly`uno ${one}, dos ${two}`, 1);
39 | });
40 |
41 | it("the 3rd parameter contains the second expression`s value", function() {
42 | function firstValueOnly(strings, firstValue, secondValue) {
43 | return secondValue;
44 | }
45 | assert.equal(firstValueOnly`uno ${one}, dos ${two}`, 2);
46 | });
47 |
48 | it("using ES6 rest syntax, all values can be accessed via one variable", function() {
49 | function valuesOnly(stringsArray, ...allValues) {
50 | // using the new ES6 rest syntax
51 | return allValues;
52 | }
53 | assert.deepEqual(valuesOnly`uno=${one}, dos=${two}, tres=${three}`, [
54 | 1,
55 | 2,
56 | 3
57 | ]);
58 | });
59 | });
60 | });
61 | });
62 |
--------------------------------------------------------------------------------
/test/es6katas/30-ArrayOfStaticMethodTest.js:
--------------------------------------------------------------------------------
1 | // 30: array - `Array.of` static method
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Array.of` creates an array with the given arguments as elements", () => {
5 | it("dont mix it up with `Array(10)`, where the argument is the array length", () => {
6 | const arr = Array.of(10);
7 |
8 | assert.deepEqual(arr, [10]);
9 | });
10 |
11 | it("puts all arguments into array elements", () => {
12 | const arr = Array.of(1, 2);
13 |
14 | assert.deepEqual(arr, [1, 2]);
15 | });
16 |
17 | it("takes any kind and number of arguments", () => {
18 | const starter = [[1, 2]];
19 | const end = [3, "4"];
20 | const arr = Array.of(...starter, ...end);
21 |
22 | assert.deepEqual(arr, [[1, 2], 3, "4"]);
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/test/es6katas/31-ArrayFillTest.js:
--------------------------------------------------------------------------------
1 | // 31: array - `Array.prototype.fill` method
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Array.prototype.fill` can fill up an array with one value", () => {
5 | it("`fill(0)` will populate `0` into each array element", function() {
6 | const arr = new Array(3).fill(0);
7 |
8 | assert.deepEqual(arr, [0, 0, 0]);
9 | });
10 |
11 | it("fill only changes content, adds no new elements", function() {
12 | const arr = [].fill(0);
13 |
14 | assert.deepEqual(arr, []);
15 | });
16 |
17 | it("second parameter to `fill()` is the position where to start filling", function() {
18 | const fillPosition = 2;
19 | const arr = [1, 2, 3].fill(42, fillPosition);
20 |
21 | assert.deepEqual(arr, [1, 2, 42]);
22 | });
23 |
24 | it("third parameter is the position where filling stops", function() {
25 | const fillStartAt = 1;
26 | const fillEndAt = 2;
27 | const arr = [1, 2, 3].fill(42, fillStartAt, fillEndAt);
28 |
29 | assert.deepEqual(arr, [1, 42, 3]);
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/test/es6katas/32-ArrayFindTest.js:
--------------------------------------------------------------------------------
1 | // 32: array - `Array.prototype.find`
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Array.prototype.find` makes finding items in arrays easier", () => {
5 | it("takes a compare function", function() {
6 | const found = [false, true].find(item => item === true);
7 |
8 | assert.equal(found, true);
9 | });
10 |
11 | it("returns the first value found", function() {
12 | const found = [0, 1, 2].find(item => item > 1);
13 |
14 | assert.equal(found, 2);
15 | });
16 |
17 | it("returns `undefined` when nothing was found", function() {
18 | const found = [1, 3].find(item => item === 2);
19 |
20 | assert.equal(found, void 0);
21 | });
22 |
23 | it("combined with destructuring complex compares become short", function() {
24 | const bob = { name: "Bob" };
25 | const alice = { name: "Alice" };
26 | const found = [bob, alice].find(({ name: { length } }) => length === 5);
27 |
28 | assert.equal(found, alice);
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/test/es6katas/33-ArrayFindIndexTest.js:
--------------------------------------------------------------------------------
1 | // 33: array - `Array.prototype.findIndex`
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Array.prototype.findIndex` makes finding items in arrays easier", () => {
5 | it("takes a compare function, returns the index where it returned true", function() {
6 | const foundAt = [false, true].findIndex(item => item === true);
7 |
8 | assert.equal(foundAt, 1);
9 | });
10 |
11 | it("returns the first position it was found at", function() {
12 | const foundAt = [0, 1, 1, 1].findIndex(item => item === 1);
13 |
14 | assert.equal(foundAt, 1);
15 | });
16 |
17 | it("returns `-1` when nothing was found", function() {
18 | const foundAt = [1, 2, 3].findIndex(item => item < 1);
19 |
20 | assert.equal(foundAt, -1);
21 | });
22 |
23 | it("the findIndex callback gets the item, index and array as arguments", function() {
24 | const three = 3;
25 | const containsThree = arr => arr.indexOf(three) > -1;
26 | function theSecondThree(item, index, arr) {
27 | const preceedingItems = arr.slice(0, index);
28 | return containsThree(preceedingItems);
29 | }
30 | const foundAt = [1, 1, 2, 3, 3, 3].findIndex(theSecondThree);
31 |
32 | assert.equal(foundAt, 4);
33 | });
34 |
35 | it("combined with destructuring complex compares become short", function() {
36 | const bob = { name: "Bob" };
37 | const alice = { name: "Alice" };
38 | const foundAt = [bob, alice].findIndex(
39 | ({ name: { length } }) => length > 3
40 | );
41 |
42 | assert.equal(foundAt, 1);
43 | });
44 | });
45 |
--------------------------------------------------------------------------------
/test/es6katas/34-SymbolTest.js:
--------------------------------------------------------------------------------
1 | // 34: symbol
2 | // A symbol is a unique and immutable data type and may be used as an identifier for object properties
3 | // read more at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol
4 |
5 | // To do: make all tests pass, leave the assert lines unchanged!
6 |
7 | describe("Symbol", function() {
8 | it("every `Symbol()` is unique", function() {
9 | const sym1 = Symbol();
10 | const sym2 = Symbol();
11 | assert.notEqual(sym1, sym2);
12 | });
13 |
14 | it("every `Symbol()` is unique, also with the same parameter", function() {
15 | const sym1 = Symbol("foo");
16 | const sym2 = Symbol("foo");
17 | assert.notEqual(sym1, sym2);
18 | });
19 |
20 | it('`typeof Symbol()` returns "symbol"', function() {
21 | const theType = typeof Symbol();
22 | assert.equal(theType, "symbol");
23 | });
24 |
25 | it("`new Symbol()` throws an exception, to prevent creation of Symbol wrapper objects", function() {
26 | function fn() {
27 | new Symbol(); // eslint-disable-line
28 | }
29 | assert.throws(fn);
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/test/es6katas/35-SymbolForTest.js:
--------------------------------------------------------------------------------
1 | // 35: Symbol.for - retrieves or creates a runtime-wide symbol
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Symbol.for` for registering Symbols globally", function() {
5 | it("creates a new symbol (check via `typeof`)", function() {
6 | const symbolType = typeof Symbol.for("symbol name");
7 | assert.equal(symbolType, "symbol");
8 | });
9 |
10 | it("stores the symbol in a runtime-wide registry and retrieves it from it", function() {
11 | const sym = Symbol.for("new symbol");
12 | const sym1 = Symbol.for("new symbol");
13 |
14 | assert.equal(sym, sym1);
15 | });
16 |
17 | it("is different to `Symbol()` which creates a symbol every time and does not store it", function() {
18 | var globalSymbol = Symbol.for("new symbol");
19 | var localSymbol = Symbol("new symbol");
20 |
21 | assert.notEqual(globalSymbol, localSymbol);
22 | });
23 |
24 | describe("`.toString()` on a Symbol", function() {
25 | const localSymbol = Symbol("new symbol");
26 | const symbolFromRegistry = Symbol.for("new symbol");
27 |
28 | it("also contains the key given to `Symbol.for()`", function() {
29 | const description = localSymbol.toString();
30 | assert.equal(description, "Symbol(new symbol)");
31 | });
32 |
33 | describe("NOTE: the description of two different symbols", function() {
34 | it("might be the same", function() {
35 | const localDescription = localSymbol.toString();
36 | const fromRegistryDescription = symbolFromRegistry.toString();
37 |
38 | assert.equal(localDescription, fromRegistryDescription);
39 | });
40 |
41 | it("but the symbols are not the same!", function() {
42 | assert.notEqual(localSymbol, symbolFromRegistry);
43 | });
44 | });
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/test/es6katas/36-KeyForTest.js:
--------------------------------------------------------------------------------
1 | // 36: Symbol.keyFor - retrieves a shared symbol key from the global symbol registry
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Symbol.keyFor()` gets the symbol key for a given symbol", function() {
5 | const sym = Symbol.for("foo");
6 |
7 | it("pass the symbol to `keyFor()` and you get its key", function() {
8 | const key = Symbol.keyFor(sym);
9 |
10 | assert.equal(key, "foo");
11 | });
12 |
13 | it("local symbols are not in the runtime-wide registry", function() {
14 | // hint: `Symbol()` creates a local symbol!
15 | const localSymbol = Symbol();
16 | const key = Symbol.keyFor(localSymbol);
17 |
18 | assert.equal(key, void 0);
19 | });
20 |
21 | it("predefined symbols are not in the runtime-wide registry either", function() {
22 | const key = Symbol.keyFor(Symbol.iterator);
23 |
24 | assert.equal(key, void 0);
25 | });
26 |
27 | it("for non-Symbols throws an error", function() {
28 | function fn() {
29 | Symbol.keyFor("");
30 | }
31 |
32 | assert.throws(fn);
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/test/es6katas/37-IteratorIterableArrayTest.js:
--------------------------------------------------------------------------------
1 | // 37: iterator/iterable - array.
2 | // The iterator protocol defines a standard way to produce a sequence of values (either finite or infinite).
3 | // read more at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
4 |
5 | // To do: make all tests pass, leave the assert lines unchanged!
6 |
7 | describe("array is a built-in iterable object", function() {
8 | const arr = ["a", "B", "see"];
9 |
10 | describe("the iterator", function() {
11 | it("an array has an iterator, which is a function", function() {
12 | const iterator = arr[Symbol.iterator];
13 | const theType = typeof iterator;
14 | const expected = "function";
15 |
16 | assert.equal(theType, expected);
17 | });
18 |
19 | it("can be looped with `for-of`, which expects an iterable", function() {
20 | let count = 0;
21 | for (let a of arr) { // eslint-disable-line
22 | count++;
23 | }
24 |
25 | assert.equal(count, arr.length);
26 | });
27 | });
28 |
29 | describe("the iterator protocol", function() {
30 | it("calling `next()` on an iterator returns an object according to the iterator protocol", function() {
31 | const iterator = arr[Symbol.iterator]();
32 | const firstItem = iterator.next();
33 |
34 | assert.deepEqual(firstItem, { done: false, value: "a" });
35 | });
36 |
37 | it("the after-last element has done=true", function() {
38 | const arr = [];
39 | const iterator = arr[Symbol.iterator]();
40 | const afterLast = iterator.next();
41 |
42 | assert.deepEqual(afterLast, { done: true, value: void 0 });
43 | });
44 | });
45 | });
46 |
--------------------------------------------------------------------------------
/test/es6katas/38-IteratorIterableStringTest.js:
--------------------------------------------------------------------------------
1 | // 38: iterator/iterable - string.
2 | // The iterator protocol defines a standard way to produce a sequence of values (either finite or infinite).
3 | // read more at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
4 |
5 | // To do: make all tests pass, leave the assert lines unchanged!
6 |
7 | describe("string is a built-in iterable object", function() {
8 | const s = "abc";
9 |
10 | describe("string is iterable", function() {
11 | it("the string`s object key `Symbol.iterator` is a function", function() {
12 | const isA = typeof s[Symbol.iterator];
13 | assert.equal(isA, "function");
14 | });
15 | it("use `Array.from()` to make an array out of any iterable", function() {
16 | const arr = Array.from(s);
17 | assert.deepEqual(arr, ["a", "b", "c"]);
18 | });
19 | });
20 |
21 | describe("a string`s iterator", function() {
22 | let iterator;
23 | beforeEach(function() {
24 | iterator = s[Symbol.iterator]();
25 | });
26 |
27 | it("has a special string representation", function() {
28 | const description = iterator.toString();
29 | assert.equal(description, "[object String Iterator]");
30 | });
31 |
32 | it("`iterator.next()` returns an object according to the iterator protocol", function() {
33 | const value = iterator.next();
34 | assert.deepEqual(value, { done: false, value: "a" });
35 | });
36 |
37 | it("the after-last call to `iterator.next()` says done=true, no more elements", function() {
38 | iterator.next();
39 | iterator.next();
40 | iterator.next();
41 | assert.equal(iterator.next().done, true);
42 | });
43 | });
44 | });
45 |
--------------------------------------------------------------------------------
/test/es6katas/39-IteratorCustomTest.js:
--------------------------------------------------------------------------------
1 | // 39: iterator - custom. Iterable is a protocol, when implemented allows objects
2 | // to customize their iteration behavior, such as what values are looped over in a for..of construct.
3 | // read more at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
4 |
5 | // To do: make all tests pass, leave the assert lines unchanged!
6 | // Follow the hints of the failure messages!
7 |
8 | describe("A simple iterable without items inside, implementing the right protocol", () => {
9 | function iteratorFunction() {
10 | return {
11 | next() {
12 | return {
13 | done: true
14 | };
15 | }
16 | };
17 | }
18 |
19 | describe("the `iteratorFunction` needs to comply to the iterator protocol", function() {
20 | it("must return an object", function() {
21 | assert.equal(typeof iteratorFunction(), "object");
22 | });
23 | it("the object must have a function assigned to a key `next`", function() {
24 | assert.equal(typeof iteratorFunction().next, "function");
25 | });
26 | it("calling `next()` must return an object with `{done: true}`", function() {
27 | assert.deepEqual(iteratorFunction().next(), { done: true });
28 | });
29 | });
30 |
31 | let iterable;
32 | beforeEach(function() {
33 | iterable = {
34 | [Symbol.iterator]: iteratorFunction
35 | };
36 | });
37 |
38 | describe("the iterable", function() {
39 | it("must be an object", function() {
40 | assert.equal(typeof iterable, "object");
41 | });
42 | it("must have the iterator function assigned to the key `Symbol.iterator`", function() {
43 | assert.equal(iterable[Symbol.iterator], iteratorFunction);
44 | });
45 | });
46 |
47 | describe("using the iterable", function() {
48 | it("it contains no values", function() {
49 | let values = "";
50 | for (let value of iterable) {
51 | values += value;
52 | }
53 | assert.equal(values, "");
54 | });
55 |
56 | it("has no `.length` property", function() {
57 | const hasLengthProperty = "length" in iterable;
58 | assert.equal(hasLengthProperty, false);
59 | });
60 |
61 | describe("can be converted to an array", function() {
62 | it("using `Array.from()`", function() {
63 | const arr = Array.from(iterable);
64 | assert.equal(Array.isArray(arr), true);
65 | });
66 |
67 | it("where `.length` is still 0", function() {
68 | const arr = Array.from(iterable);
69 | const length = arr.length;
70 | assert.equal(length, 0);
71 | });
72 | });
73 | });
74 | });
75 |
--------------------------------------------------------------------------------
/test/es6katas/4-TemplateStringsRawStringTest.js:
--------------------------------------------------------------------------------
1 | // 4: template strings - String.raw
2 | // To do: make all tests pass, leave the asserts unchanged!
3 |
4 | describe("on tagged template strings you can use the `raw` property like so `s.raw`", function() {
5 | it("the `raw` property accesses the string as it was entered", function() {
6 | function firstChar(strings) {
7 | return strings.raw;
8 | }
9 | assert.equal(firstChar`\n`, "\\n");
10 | });
11 |
12 | it("`raw` can access the backslash of a line-break", function() {
13 | function firstCharEntered(strings) {
14 | var lineBreak = strings.raw;
15 | return lineBreak[0][0];
16 | }
17 | assert.equal(firstCharEntered`\n`, "\\");
18 | });
19 |
20 | describe("`String.raw` as a static function", function() {
21 | it("concats the raw strings", function() {
22 | var expected = "\\n";
23 | assert.equal(String.raw`\n`, expected);
24 | });
25 |
26 | it("two raw-templates-string-backslashes equal two escaped backslashes", function() {
27 | const TWO_BACKSLASHES = "\\\\";
28 | assert.equal(String.raw`\\`, TWO_BACKSLASHES);
29 | });
30 |
31 | it("works on unicodes too", function() {
32 | var smilie = "\\u{1F600}";
33 | var actual = String.raw`\u{1F600}`;
34 | assert.equal(actual, smilie);
35 | });
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/test/es6katas/40-IteratorExampleUsageTest.js:
--------------------------------------------------------------------------------
1 | // 40: iterator - one example usage. Build an iterable and use it with some built-in ES6 constructs.
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | // Consumable users:
5 | // - `consumableUser` contains a consumable user,
6 | // - `anyLeft` tells if there is any user left that can be consumed.
7 |
8 | class ConsumableUsers {
9 | constructor() {
10 | this.users = ["Alice", "Bob"];
11 | this.empty = false;
12 | }
13 | get nextUser() {
14 | if (this.users.length > 0) {
15 | return `user: ${this.users.shift()}`;
16 | }
17 | this.empty = true;
18 | return void 0;
19 | }
20 | get anyLeft() {
21 | return this.empty;
22 | }
23 | }
24 |
25 | describe("Iterator usages", () => {
26 | let usersIterable;
27 | beforeEach(function() {
28 | const consumableUsers = new ConsumableUsers();
29 | function iteratorFunction() {
30 | return {
31 | next: function() {
32 | return {
33 | value: consumableUsers.nextUser,
34 | done: consumableUsers.anyLeft
35 | };
36 | }
37 | };
38 | }
39 |
40 | usersIterable = {};
41 | usersIterable[Symbol.iterator] = iteratorFunction;
42 | });
43 |
44 | describe("create an iterator/iterable", function() {
45 | it("the `usersIterable` should be iterable", function() {
46 | const isIterable = Symbol.iterator in usersIterable;
47 | assert.equal(isIterable, true);
48 | });
49 |
50 | it("the iterator of `usersIterable` should return an object", function() {
51 | const iterator = usersIterable[Symbol.iterator]();
52 | assert.equal(typeof iterator, "object");
53 | });
54 |
55 | it("the iterator of `usersIterable` should have a next function", function() {
56 | const iterator = usersIterable[Symbol.iterator]();
57 | assert.equal(typeof iterator.next, "function");
58 | });
59 | });
60 |
61 | describe("fill the iterable with content using `ConsumableUsers`", function() {
62 | describe("using the iterator", function() {
63 | let iterator;
64 | beforeEach(function() {
65 | iterator = usersIterable[Symbol.iterator]();
66 | });
67 | it("should return `Alice` as first user", function() {
68 | const firstItem = iterator.next();
69 | assert.deepEqual(firstItem, { value: "user: Alice", done: false });
70 | });
71 | it("should return `Bob` as second user", function() {
72 | iterator.next(); // drop the first item
73 | const secondItem = iterator.next();
74 | assert.deepEqual(secondItem, { value: "user: Bob", done: false });
75 | });
76 | it("should return `done:true`, which means there are no more items", function() {
77 | iterator.next();
78 | iterator.next();
79 | const beyondLast = iterator.next();
80 | assert.deepEqual(beyondLast, { value: void 0, done: true });
81 | });
82 | });
83 |
84 | describe("using built-in constructs", function() {
85 | it("use `Array.from()` to convert an iterable to an array", function() {
86 | const users = Array.from(usersIterable);
87 | assert.deepEqual(users, ["user: Alice", "user: Bob"]);
88 | });
89 | it("use for-of to loop over an iterable", function() {
90 | const users = [];
91 | for (let user of usersIterable) users.push(user);
92 | assert.deepEqual(users, ["user: Alice", "user: Bob"]);
93 | });
94 | it("use the spread-operator to convert/add iterable to an array", function() {
95 | const users = ["noname", ...usersIterable];
96 | assert.deepEqual(users, ["noname", "user: Alice", "user: Bob"]);
97 | });
98 | it("destructure an iterable like an array", function() {
99 | const [firstUser, secondUser] = usersIterable;
100 | assert.equal(firstUser, "user: Alice");
101 | assert.equal(secondUser, "user: Bob");
102 | });
103 | });
104 | });
105 | });
106 |
--------------------------------------------------------------------------------
/test/es6katas/41-ArrayEntriesTest.js:
--------------------------------------------------------------------------------
1 | // 41: array - entries
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`[].entries()` returns an iterator object with all entries", function() {
5 | it("returns key+value for each element", function() {
6 | const arr = ["a", "b", "c"];
7 | const entriesAsArray = Array.from(arr.entries());
8 |
9 | assert.deepEqual(entriesAsArray, [[0, "a"], [1, "b"], [2, "c"]]);
10 | });
11 |
12 | it("empty elements contain the value `undefined`", function() {
13 | const arr = ["one"];
14 | arr[2] = "three";
15 | const secondValue = Array.from(arr.entries())[1];
16 |
17 | assert.deepEqual(secondValue, [1, void 0]);
18 | });
19 |
20 | describe("returns an iterable", function() {
21 | it("has `next()` to iterate", function() {
22 | const arr = ["one"];
23 | const value = arr.entries().next().value;
24 |
25 | assert.deepEqual(value, [0, "one"]);
26 | });
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/test/es6katas/42-ArrayKeysTest.js:
--------------------------------------------------------------------------------
1 | // 42: array - `Array.prototype.keys`
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Array.prototype.keys` returns an iterator for all keys in the array", () => {
5 | it("`keys()` returns an iterator", function() {
6 | const arr = ["a"];
7 | const iterator = arr.keys();
8 |
9 | assert.deepEqual(iterator.next(), { value: 0, done: false });
10 | assert.deepEqual(iterator.next(), { value: void 0, done: true });
11 | });
12 |
13 | it("gets all keys", function() {
14 | const arr = [0, 1, 2];
15 | const keys = Array.from(arr.keys());
16 |
17 | assert.deepEqual(keys, [0, 1, 2]);
18 | });
19 |
20 | it("empty array contains no keys", function() {
21 | const arr = [];
22 | const keys = [...arr.keys()];
23 |
24 | assert.equal(keys.length, 0);
25 | });
26 |
27 | it("a sparse array without real values has keys though", function() {
28 | const arr = [, ,]; // eslint-disable-line
29 | const keys = [...arr.keys()];
30 |
31 | assert.deepEqual(keys, [0, 1]);
32 | });
33 |
34 | it("also includes holes in sparse arrays", function() {
35 | const arr = ["a", , "c"]; // eslint-disable-line
36 | const keys = [...arr.keys()];
37 |
38 | assert.deepEqual(keys, [0, 1, 2]);
39 | });
40 | });
41 |
--------------------------------------------------------------------------------
/test/es6katas/44-MapBasicsTest.js:
--------------------------------------------------------------------------------
1 | // 44: Map - basics
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Map` is a key/value map", function() {
5 | it("`Map` is a new global constructor function", function() {
6 | assert.equal(typeof Map, "function");
7 | });
8 |
9 | it("provides `new Map().set()` to add key+value pair, `get()` to read it by key", function() {
10 | let map = new Map();
11 | map.set("key", "value");
12 | const value = map.get("key");
13 |
14 | assert.equal(value, "value");
15 | });
16 |
17 | it("`has()` tells if map has the given key", function() {
18 | let map = new Map();
19 | map.set("key", "value");
20 | const hasIt = map.has("key");
21 |
22 | assert.equal(hasIt, true);
23 | });
24 |
25 | it("a map is iterable", function() {
26 | let map = new Map();
27 | map.set("1", "one");
28 | map.set("2", "two");
29 | const mapAsArray = Array.from(map); // hint: kata #29 http://tddbin.com/#?kata=es6/language/array-api/from
30 |
31 | assert.deepEqual(mapAsArray, [["1", "one"], ["2", "two"]]);
32 | });
33 |
34 | it("complex types can be keys", function() {
35 | const obj = { x: 1 };
36 | const otherObj = { x: 1 };
37 | let map = new Map();
38 | map.set(obj, "");
39 |
40 | assert.equal(map.has(otherObj), false);
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/test/es6katas/45-MapGetTest.js:
--------------------------------------------------------------------------------
1 | // 45: Map.prototype.get()
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Map.prototype.get` returns the element from the map for a key", function() {
5 | it("`get(key)` returns the value stored for this key", function() {
6 | let map = new Map();
7 | map.set("key", "value");
8 |
9 | const value = map.get("key");
10 | assert.equal(value, "value");
11 | });
12 |
13 | it("multiple calls still return the same value", function() {
14 | let map = new Map();
15 | map.set("value", "value");
16 |
17 | var value = map.get(map.get(map.get("value")));
18 | assert.equal(value, "value");
19 | });
20 |
21 | it("requires exactly the value as passed to `set()`", function() {
22 | let map = new Map();
23 | const obj = {};
24 | map.set(obj, "object is key");
25 |
26 | assert.equal(map.get(obj), "object is key");
27 | });
28 |
29 | it("leave out the key, and you get the value set for the key `undefined` (void 0)", function() {
30 | let map = new Map();
31 | map.set(void 0, "yo");
32 |
33 | const value = map.get();
34 | assert.equal(value, "yo");
35 | });
36 |
37 | it("returns undefined for an unknown key", function() {
38 | let map = new Map();
39 |
40 | const value = map.get();
41 | assert.equal(value, void 0);
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/test/es6katas/46-MapSetTest.js:
--------------------------------------------------------------------------------
1 | // 46: Map.prototype.set()
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Map.prototype.set` adds a new element with key and value to a Map", function() {
5 | it("simplest use case is `set(key, value)` and `get(key)`", function() {
6 | let map = new Map();
7 | map.set("key", "value");
8 |
9 | assert.equal(map.get("key"), "value");
10 | });
11 |
12 | it("the key can be a complex type too", function() {
13 | const noop = function() {};
14 | let map = new Map();
15 | map.set(noop, "the real noop");
16 |
17 | assert.equal(map.get(noop), "the real noop");
18 | });
19 |
20 | it("calling `set()` again with the same key replaces the value", function() {
21 | let map = new Map();
22 | map.set("key", "value");
23 | map.set("key", "value1");
24 |
25 | assert.equal(map.get("key"), "value1");
26 | });
27 |
28 | it("`set()` returns the map object, it`s chainable", function() {
29 | let map = new Map();
30 | map
31 | .set(1, "one")
32 | .set(2, "two")
33 | .set(3, "three");
34 |
35 | assert.deepEqual([...map.keys()], [1, 2, 3]);
36 | assert.deepEqual([...map.values()], ["one", "two", "three"]);
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/test/es6katas/47-SetBasicsTest.js:
--------------------------------------------------------------------------------
1 | // 47: Set - basics
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Set` lets you store unique values of any type", function() {
5 | it("`Set` is a new global constructor function", function() {
6 | assert.equal(typeof Set, "function");
7 | });
8 |
9 | it("every value in a set is unique", function() {
10 | let set = new Set();
11 |
12 | set.add(1);
13 | set.add(2);
14 | const expectedSize = 2;
15 |
16 | assert.equal(set.size, expectedSize);
17 | });
18 |
19 | it('the string "1" is different to the number 1', function() {
20 | let set = new Set();
21 | set.add(1);
22 | set.add("1");
23 |
24 | assert.equal(set.size, 2);
25 | });
26 |
27 | it("even NaN is equal to NaN", function() {
28 | let set = new Set();
29 | set.add(NaN);
30 | set.add(NaN);
31 |
32 | assert.equal(set.size, 1);
33 | });
34 |
35 | it("+0 and -0 are seen as equal", function() {
36 | let set = new Set();
37 | set.add(+0);
38 | set.add(-0);
39 |
40 | assert.deepEqual([...set.values()], [+0]);
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/test/es6katas/48-SetAddTest.js:
--------------------------------------------------------------------------------
1 | // 48: Set - add
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`add()` appends a new element to the end of a Set object.", function() {
5 | let set;
6 | beforeEach(() => (set = new Set()));
7 |
8 | it("adds every value, of any type, only once", function() {
9 | const fn = () => {};
10 |
11 | set.add(1);
12 | set.add(1);
13 | set.add(fn);
14 | set.add(fn);
15 |
16 | assert.equal(set.size, 2);
17 | });
18 |
19 | it("is chainable", function() {
20 | set.add(1).add(2);
21 |
22 | assert.equal(set.has(2), true);
23 | });
24 |
25 | it("call without params adds undefined", function() {
26 | set.add();
27 |
28 | assert.equal(set.has(void 0), true);
29 | });
30 |
31 | it("0, -0 and +0 are equal", function() {
32 | set.add(0);
33 | set.add(-0);
34 | set.add(+0);
35 |
36 | assert.equal(set.has(+0), true);
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/test/es6katas/5-ArrowFunctionsBasicTest.js:
--------------------------------------------------------------------------------
1 | // 5: arrow functions - basics
2 | // To do: make all tests pass, leave the asserts unchanged!
3 |
4 | describe("arrow functions", function() {
5 | it("are shorter to write", function() {
6 | var func = () => {
7 | return "I am func";
8 | };
9 | assert.equal(func(), "I am func");
10 | });
11 |
12 | it("a single expression, without curly braces returns too", function() {
13 | var func = () => "I return too";
14 | assert.equal(func(), "I return too");
15 | });
16 |
17 | it("one parameter can be written without parens", () => {
18 | var func = param => param - 1;
19 | assert.equal(func(25), 24);
20 | });
21 |
22 | it("many params require parens", () => {
23 | var func = (param, param1) => param + param1;
24 | assert.equal(func(23, 42), 23 + 42);
25 | });
26 |
27 | it("body needs parens to return an object", () => {
28 | var func = () => {
29 | return { iAm: "an object" };
30 | };
31 | assert.deepEqual(func(), { iAm: "an object" });
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/test/es6katas/53-MapInitializeTest.js:
--------------------------------------------------------------------------------
1 | // 53: Map - initialize
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("initialize a `Map`", function() {
5 | it("a `new Map()` is empty, has size=0", function() {
6 | const mapSize = new Map().size;
7 | assert.equal(mapSize, 0);
8 | });
9 |
10 | it("init Map with `[[]]` has a size=1", function() {
11 | const mapSize = new Map([[]]).size;
12 |
13 | assert.equal(mapSize, 1);
14 | });
15 |
16 | it("init a Map with `[[1]]` is the same as `map.set(1, void 0)`", function() {
17 | let map1 = new Map([[1]]);
18 | let map2 = new Map().set(1, void 0);
19 |
20 | assertMapsEqual(map1, map2);
21 | });
22 |
23 | it("init Map with multiple key+value pairs", function() {
24 | const pair1 = [1, "one"];
25 | const pair2 = [2, "two"];
26 |
27 | const map = new Map([pair1, pair2]);
28 |
29 | assertMapsEqual(map, new Map().set(...pair1).set(...pair2));
30 | });
31 |
32 | it("keys are unique, the last one is used", function() {
33 | const pair1 = [1, "one"];
34 | const pair2 = [1, "uno"];
35 | const pair3 = [1, "eins"];
36 | const pair4 = [2, "two"];
37 |
38 | const map = new Map([pair1, pair2, pair3, pair4]);
39 |
40 | assertMapsEqual(map, new Map().set(...pair3).set(...pair4));
41 | });
42 |
43 | it("init Map from an Object, is a bit of work", function() {
44 | let map = new Map();
45 | const obj = { x: 1, y: 2 };
46 | const keys = Object.keys(obj);
47 | keys.forEach(key => map.set(key, obj[key]));
48 |
49 | const expectedEntries = [["x", 1], ["y", 2]];
50 | assertMapsEqual(map, expectedEntries);
51 | });
52 | });
53 |
54 | function mapToArray(map) {
55 | return Array.from(map);
56 | }
57 | function assertMapsEqual(map1, map2) {
58 | assert.deepEqual(mapToArray(map1), mapToArray(map2));
59 | }
60 |
--------------------------------------------------------------------------------
/test/es6katas/54-ObjectIsTest.js:
--------------------------------------------------------------------------------
1 | // 54: Object - is
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Object.is()` determines whether two values are the same", function() {
5 | describe("scalar values", function() {
6 | it("1 is the same as 1", function() {
7 | const areSame = Object.is(1, 1);
8 | assert.equal(areSame, true);
9 | });
10 | it('int 1 is different to string "1"', function() {
11 | const areSame = Object.is(1, "1");
12 | assert.equal(areSame, false);
13 | });
14 | it("strings just have to match", function() {
15 | const areSame = Object.is("one", "one");
16 | assert.equal(areSame, true);
17 | });
18 | it("+0 is not the same as -0", function() {
19 | const areSame = false;
20 | assert.equal(Object.is(+0, -0), areSame);
21 | });
22 | it("NaN is the same as NaN", function() {
23 | const number = NaN;
24 | assert.equal(Object.is(NaN, number), true);
25 | });
26 | });
27 |
28 | describe("coercion, as in `==` and `===`, does NOT apply", function() {
29 | it("+0 != -0", function() {
30 | const coerced = +0 === -0; // eslint-disable-line
31 | const isSame = !Object.is(+0, -0);
32 | assert.equal(isSame, coerced);
33 | });
34 | it("empty string and `false` are not the same", function() {
35 | const emptyString = "";
36 | const isSame = !Object.is(emptyString, false);
37 | assert.equal(isSame, emptyString == false);
38 | });
39 | it("NaN", function() {
40 | const coerced = NaN == NaN; // eslint-disable-line
41 | const isSame = !Object.is(NaN, NaN);
42 | assert.equal(isSame, coerced);
43 | });
44 | it("NaN 0/0", function() {
45 | const isSame = Object.is(NaN, 0 / 0);
46 | assert.equal(isSame, true);
47 | });
48 | });
49 |
50 | describe("complex values", function() {
51 | it("`{}` is just not the same as `{}`", function() {
52 | const areSame = false;
53 | assert.equal(Object.is({}, {}), areSame);
54 | });
55 | it("Map", function() {
56 | let map1 = new Map([[1, "one"]]);
57 | let map2 = new Map([[1, "one"]]);
58 | const areSame = Object.is(map1, map2);
59 | assert.equal(areSame, false);
60 | });
61 | });
62 | });
63 |
--------------------------------------------------------------------------------
/test/es6katas/55-NumberIsIntegerTest.js:
--------------------------------------------------------------------------------
1 | // 55: Number - isInteger
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Number.isInteger()` determines if a value is an integer", function() {
5 | const isTrue = what => assert.equal(what, true);
6 | const isFalse = what => assert.equal(what, false);
7 |
8 | it("`isInteger` is a static function on `Number`", function() {
9 | const whatType = "function";
10 | assert.equal(typeof Number.isInteger, whatType);
11 | });
12 |
13 | describe("zero in different ways", function() {
14 | it("0 is an integer", function() {
15 | const zero = 0;
16 | isTrue(Number.isInteger(zero));
17 | });
18 | it("0.000", function() {
19 | isTrue(Number.isInteger(0.0));
20 | });
21 | it('the string "0" is NOT an integer', function() {
22 | const stringZero = "0";
23 | isFalse(Number.isInteger(stringZero));
24 | });
25 | });
26 |
27 | describe("one in different ways", function() {
28 | it("0.111 + 0.889", function() {
29 | const rest = 0.889;
30 | isTrue(Number.isInteger(0.111 + rest));
31 | });
32 | it("0.5 + 0.2 + 0.2 + 0.1 = 1 ... isn`t it?", function() {
33 | const oneOrNot = 0.5 + 0.2 + 0.2 + 0.1;
34 | isFalse(Number.isInteger(oneOrNot));
35 | });
36 | it('parseInt`ed "1" is an integer', function() {
37 | const convertedToInt = Number.parseInt("1.01");
38 | isTrue(Number.isInteger(convertedToInt));
39 | });
40 | });
41 |
42 | describe("what is not an integer", function() {
43 | it("`Number()` is an integer", function() {
44 | const numberOne = Number();
45 | isTrue(Number.isInteger(numberOne));
46 | });
47 | it("`{}` is NOT an integer", function() {
48 | const isit = Number.isInteger({});
49 | isFalse(isit);
50 | });
51 | it("`0.1` is not an integer", function() {
52 | const isit = Number.isInteger(0.1);
53 | isFalse(isit);
54 | });
55 | it("`Number.Infinity` is not an integer", function() {
56 | const isit = Number.isInteger(Number.POSITIVE_INFINITY);
57 | isFalse(isit);
58 | });
59 | it("`NaN` is not an integer", function() {
60 | const isit = Number.isInteger(NaN);
61 | isFalse(isit);
62 | });
63 | });
64 | });
65 |
--------------------------------------------------------------------------------
/test/es6katas/57-DefaultParametersTest.js:
--------------------------------------------------------------------------------
1 | // 57: Default parameters - basics
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("default parameters make function parameters more flexible", () => {
5 | it("define it using an assignment to the parameter `function(param=1){}`", function() {
6 | let number = (int = 0) => int;
7 |
8 | assert.equal(number(), 0);
9 | });
10 |
11 | it("it is used when undefined is passed", function() {
12 | let number = function(int = 23) {
13 | return int;
14 | };
15 | const param = 23;
16 |
17 | assert.equal(number(param), 23);
18 | });
19 |
20 | it("it is not used when a value is given", function() {
21 | function xhr(method = "GET") {
22 | return method;
23 | }
24 |
25 | assert.equal(xhr("POST"), "POST");
26 | });
27 |
28 | it("it is evaluated at run time", function() {
29 | let defaultValue = 42;
30 | function xhr(method = `value: ${defaultValue}`) {
31 | return method;
32 | }
33 |
34 | assert.equal(xhr(), "value: 42");
35 | defaultValue = 43;
36 | });
37 |
38 | it("it can also be a function", function() {
39 | let defaultValue = function() {};
40 | function fn(value = defaultValue()) {
41 | return value;
42 | }
43 |
44 | assert.equal(fn(), defaultValue());
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/test/es6katas/58-ReflectBasicsTest.js:
--------------------------------------------------------------------------------
1 | // 58: Reflect - basics
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Reflect` basics", function() {
5 | describe("Reflect is special, it is different to e.g. `Object`", function() {
6 | it("is not a function", function() {
7 | const expectedType = "object";
8 | assert.equal(typeof Reflect, expectedType);
9 | });
10 |
11 | it("it can not be instantiated", function() {
12 | const tryToConstruct = () => {
13 | new Reflect();
14 | };
15 | assert.throws(tryToConstruct, TypeError);
16 | });
17 |
18 | it("has no `call` method (as opposed to e.g. Object)", function() {
19 | const expected = "undefined";
20 | assert.equal(typeof Reflect.call, expected);
21 | });
22 | });
23 |
24 | describe("some `Reflect` usages", function() {
25 | it("`Reflect.construct()` is like new", function() {
26 | class Class {}
27 |
28 | assert.equal(Reflect.construct(Class, []) instanceof Class, true);
29 | });
30 |
31 | it("`Reflect.get()` returns a property`s value", function() {
32 | let obj = { x: 23 };
33 | assert.equal(Reflect.get(obj, "x"), 23);
34 | });
35 |
36 | it("`Reflect.has()` is like `in` just as a function", function() {
37 | let obj = { x: 11 };
38 | assert.equal(Reflect.has(obj, "x"), true);
39 | });
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/test/es6katas/59-ReflectApplyTest.js:
--------------------------------------------------------------------------------
1 | // 59: Reflect - apply
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Reflect.apply` calls a target function", function() {
5 | it("it is a static method", function() {
6 | const expectedType = "function";
7 |
8 | assert.equal(typeof Reflect.apply, expectedType);
9 | });
10 |
11 | it("passing it a non-callable throws a TypeError", function() {
12 | let applyOnUncallable = () => {
13 | Reflect.apply([]);
14 | };
15 |
16 | assert.throws(applyOnUncallable, TypeError);
17 | });
18 |
19 | it("the 3rd argument is an array of parameters passed to the call", function() {
20 | let emptyArrayWithFiveElements = Reflect.apply(Array, this, [5]);
21 |
22 | assert.deepEqual(emptyArrayWithFiveElements.fill(42), [42, 42, 42, 42, 42]);
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/test/es6katas/6-ArrowFunctionsBindingTest.js:
--------------------------------------------------------------------------------
1 | // 6: arrow functions - binding
2 | // To do: make all tests pass, leave the asserts unchanged!
3 |
4 | class LexicallyBound {
5 | getFunction() {
6 | return () => {
7 | return this;
8 | };
9 | }
10 |
11 | getArgumentsFunction() {
12 | return () => {
13 | return arguments;
14 | };
15 | }
16 | }
17 |
18 | describe("arrow functions have lexical `this`, no dynamic `this`", () => {
19 | it("bound at definition time, use `=>` ", function() {
20 | var bound = new LexicallyBound();
21 | var fn = bound.getFunction();
22 |
23 | assert.strictEqual(fn(), bound);
24 | });
25 |
26 | it("can NOT bind a different context", function() {
27 | var bound = new LexicallyBound();
28 | var fn = bound.getFunction();
29 | var anotherObj = {};
30 | var expected = bound;
31 |
32 | assert.strictEqual(fn.call(anotherObj), expected);
33 | });
34 |
35 | it("`arguments` doesnt work inside arrow functions", function() {
36 | var bound = new LexicallyBound();
37 | var fn = bound.getArgumentsFunction();
38 |
39 | assert.equal(fn(1, 2).length, 0);
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/test/es6katas/60-ReflectGetPrototypeOfTest.js:
--------------------------------------------------------------------------------
1 | // 60: Reflect - getPrototypeOf
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Reflect.getPrototypeOf` returns the prototype", function() {
5 | it("works like `Object.getPrototypeOf`", function() {
6 | const viaObject = Object.getPrototypeOf({});
7 | const viaReflect = Reflect.getPrototypeOf({});
8 |
9 | assert.strictEqual(viaObject, viaReflect);
10 | });
11 |
12 | it("throw TypeError for a non-object", function() {
13 | let fn = () => {
14 | Reflect.getPrototypeOf();
15 | };
16 | assert.throws(fn, TypeError);
17 | });
18 |
19 | it("a `new Set()` has a prototype", function() {
20 | const aSet = new Set();
21 |
22 | assert.equal(Reflect.getPrototypeOf(aSet), Set.prototype);
23 | });
24 |
25 | it("for a class, it is `Klass.prototype`", function() {
26 | class Klass {}
27 | const proto = Reflect.getPrototypeOf(new Klass());
28 |
29 | assert.equal(proto, Klass.prototype);
30 | });
31 |
32 | it("for a old-style class, works too", function() {
33 | function Klass() {}
34 | const proto = Reflect.getPrototypeOf(new Klass());
35 |
36 | assert.equal(proto, Klass.prototype);
37 | });
38 |
39 | it("an array has a prototype too", function() {
40 | let arr = [];
41 | const expectedProto = Array.prototype;
42 |
43 | assert.equal(Reflect.getPrototypeOf(arr), expectedProto);
44 | });
45 | });
46 |
--------------------------------------------------------------------------------
/test/es6katas/61-ModulesImportTest.js:
--------------------------------------------------------------------------------
1 | // 61: modules - import
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | import { equal, deepEqual, notEqual } from "assert"; // eslint-disable-line
5 | import { equal as myEqual, default as myAssert } from "assert"; // eslint-disable-line
6 |
7 | describe("use `import` to import functions that have been exported (somewhere else)", function() {
8 | describe("the import statement", function() {
9 | it("is only allowed on the root level", function() {
10 | // try to comment this out, it will yell at you :)
11 | // import assert from 'assert'; // eslint-disabled-line
12 | });
13 |
14 | it('import an entire module using `import from ""`', function() {
15 | // this can't fail, since `assert` is imported by default
16 | assert.equal(typeof assert, "function");
17 | });
18 | });
19 |
20 | describe("import members", function() {
21 | it('import a single member, using `import {} from "module"`', function() {
22 | assert.strictEqual(equal, assert.equal);
23 | });
24 | describe("separate multiple members with a comma", function() {
25 | it("`deepEqual` from the assert module", () => {
26 | assert.strictEqual(deepEqual, assert.deepEqual);
27 | });
28 | it("`notEqual` from the assert module", () => {
29 | assert.strictEqual(notEqual, assert.notEqual);
30 | });
31 | });
32 | });
33 |
34 | describe("alias imports", function() {
35 | it("using `member as alias` as memberName", function() {
36 | assert.strictEqual(myEqual, assert.equal);
37 | });
38 | it("rename the default export of a module, using `default as alias` as memberName", function() {
39 | assert.strictEqual(myAssert, assert);
40 | });
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/test/es6katas/62-MapHasTest.js:
--------------------------------------------------------------------------------
1 | // 62: Map - `has()`
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`map.has()` indicates whether an element with a key exists", function() {
5 | it("finds nothing in an empty map", function() {
6 | let map = new Map();
7 | const hasKey = map.has(void 0);
8 | assert.equal(hasKey, false);
9 | });
10 |
11 | it("finds an element by it`s key", function() {
12 | let map = new Map([["key", "VALUE"]]);
13 | const hasKey = map.has("key");
14 | assert.equal(hasKey, true);
15 | });
16 |
17 | it("finds `undefined` as key too", function() {
18 | let map = new Map([[void 0, "not defined key"]]);
19 | const hasUndefinedAsKey = map.has(void 0);
20 | assert.equal(hasUndefinedAsKey, true);
21 | });
22 |
23 | it("does not coerce keys", function() {
24 | let map = new Map([[1, "one"]]);
25 | const findsStringOne = false;
26 | assert.equal(map.has("1"), findsStringOne);
27 | });
28 |
29 | it("after removal (using `map.delete()`) it doesnt find the element anymore", function() {
30 | let map = new Map([[1, "one"]]);
31 | map.delete(1);
32 | assert.equal(map.has(1), false);
33 | });
34 |
35 | it("adding an item (using `map.set(key, value)`) later will make `has()` return true", function() {
36 | let map = new Map();
37 | map.set(void 0, 1);
38 | assert.equal(map.has(void 0), true);
39 | });
40 | });
41 |
--------------------------------------------------------------------------------
/test/es6katas/63-StringIncludesTest.js:
--------------------------------------------------------------------------------
1 | // 63: String - `includes()`
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`string.includes()` finds string within another string", function() {
5 | describe("find a single character", function() {
6 | it("in a three char string", function() {
7 | const searchString = "x";
8 | assert.equal("xyz".includes(searchString), true);
9 | });
10 | it("reports false if character was not found", function() {
11 | const expected = false;
12 | assert.equal("xyz".includes("abc"), expected);
13 | });
14 | });
15 |
16 | describe("find a string", function() {
17 | it("that matches exactly", function() {
18 | const findSome = findMe => "xyz".includes(findMe);
19 | assert.equal(findSome("xyz"), true);
20 | });
21 | });
22 |
23 | describe("search for an empty string, is always true", function() {
24 | it("in an empty string", function() {
25 | const emptyString = "";
26 | assert.equal("".includes(emptyString), true);
27 | });
28 | it("in `abc`", function() {
29 | const actual = "abc".includes("");
30 | assert.equal(actual, true);
31 | });
32 | });
33 |
34 | describe("special/corner cases", function() {
35 | it("search for `undefined` in a string fails", function() {
36 | const findInAbc = what => "abc".includes(what);
37 | assert.equal(findInAbc(void 0), false);
38 | });
39 | it("searches case-sensitive", function() {
40 | const findInAbc = what => "abc".includes(what);
41 | assert.equal(findInAbc("A"), false);
42 | });
43 | it("must NOT be a regular expression", function() {
44 | const regExp = /.+/;
45 | assert.throws(() => {
46 | "".includes(regExp);
47 | });
48 | });
49 | describe('coerces the searched "thing" into a string', function() {
50 | it("e.g. from a number", function() {
51 | const actual = "123".includes(123);
52 | assert.equal(actual, true);
53 | });
54 | it("e.g. from an array", function() {
55 | const actual = "123".includes([1]);
56 | assert.equal(actual, true);
57 | });
58 | it("e.g. from an object, with a `toString()` method", function() {
59 | const objWithToString = { toString: () => "123" };
60 | assert.equal("123".includes(objWithToString), true);
61 | });
62 | });
63 | });
64 |
65 | describe("takes a position from where to start searching", function() {
66 | it("does not find `a` after position 1 in `abc`", function() {
67 | const position = 1;
68 | assert.equal("abc".includes("a", position), false);
69 | });
70 | it("even the position gets coerced", function() {
71 | const findAtPosition = pos => "xyz".includes("z", pos);
72 | assert.equal(findAtPosition("2"), true);
73 | });
74 | describe("invalid positions get converted to 0", function() {
75 | it("e.g. `undefined`", function() {
76 | const findAtPosition = (pos = 0) => "xyz".includes("x", pos);
77 | assert.equal(findAtPosition(void 0), true);
78 | });
79 | it("negative numbers", function() {
80 | const findAtPosition = pos => "xyz".includes("x", pos);
81 | assert.equal(findAtPosition(-2), true);
82 | });
83 | it("NaN", function() {
84 | const findAtPosition = pos => "xyz".includes("x", pos);
85 | assert.equal(findAtPosition(NaN), true);
86 | });
87 | });
88 | });
89 | });
90 |
--------------------------------------------------------------------------------
/test/es6katas/64-SetDeleteTest.js:
--------------------------------------------------------------------------------
1 | // 64: Set - delete
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`set.delete()` deletes an element from a set", function() {
5 | let set;
6 | beforeEach(() => (set = new Set()));
7 |
8 | describe("use `delete()` to delete an element", function() {
9 | beforeEach(function() {
10 | set
11 | .add("one")
12 | .add("two")
13 | .add("three");
14 | });
15 | it("`delete()` returns `true` when the element was found", function() {
16 | const returns = set.delete("one");
17 | assert.strictEqual(returns, true);
18 | });
19 | it("and the size decreases", function() {
20 | set.delete("one");
21 | assert.equal(set.size, 2);
22 | });
23 | });
24 |
25 | describe("if nothing was deleted (no element with the given value was found)", function() {
26 | it("returns `false`", function() {
27 | set.add("one");
28 | const returns = set.delete("1");
29 |
30 | assert.equal(returns, false);
31 | });
32 | });
33 |
34 | describe("`undefined` is a valid value in a set", function() {
35 | it("deleting it, when it is not in the set, returns `false` too", function() {
36 | assert.equal(set.delete(void 0), false);
37 | });
38 |
39 | it("`delete()` removes it, when its in the set", function() {
40 | set.add();
41 | assert.equal(set.delete(), true);
42 | });
43 | });
44 |
45 | describe("the value does NOT get casted", function() {
46 | it('number 1 is different to string "1"', function() {
47 | set.add(1);
48 | assert.equal(set.delete("1"), false);
49 | });
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/test/es6katas/65-SetApiOverviewTest.js:
--------------------------------------------------------------------------------
1 | // 65: Set - API overview
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Set` API overview", function() {
5 | const api = [
6 | "size",
7 | "add",
8 | "clear",
9 | "delete",
10 | "entries",
11 | "forEach",
12 | "has",
13 | "keys",
14 | "values"
15 | ];
16 | let set;
17 | beforeEach(function() {
18 | set = new Set(api);
19 | });
20 |
21 | it("a Set can be created from an array", function() {
22 | let set = new Set(api);
23 | assert.deepEqual(Array.from(set), api);
24 | });
25 |
26 | it("`size` is the number of values", function() {
27 | const theSize = set.size;
28 | assert.equal(theSize, api.length);
29 | });
30 |
31 | it("`add()` appends the given value", function() {
32 | // hint: to make the example consistent you can add the `Symbol.iterator` to `set`
33 | // strongly speaking it is missing in the API.
34 | set.add(Symbol.iterator);
35 | assert.equal(set.size, api.length + 1);
36 | });
37 |
38 | it("`clear()` removes all elements", function() {
39 | set.clear();
40 | assert.equal(set.size, 0);
41 | });
42 |
43 | it("`delete()` removes the given value", function() {
44 | set.delete(api[1]);
45 | assert.equal(set.size, api.length - 1);
46 | });
47 |
48 | it("`entries()` returns an iterator for all values", function() {
49 | const expectedEntries = api.map(entry => [entry, entry]);
50 | const actualEntries = set.entries();
51 | assert.deepEqual([...actualEntries], expectedEntries);
52 | });
53 |
54 | it("`forEach()` calls a callback for each value", function() {
55 | let values = [];
56 | set.forEach(value => {
57 | values.push(value);
58 | });
59 | assert.deepEqual(values, api);
60 | });
61 |
62 | it("`has()` returns true if the given value is in the set", function() {
63 | const propertyName = "size";
64 | assert.equal(set.has(propertyName), true);
65 | });
66 |
67 | describe("returns an iterator that contains all values", function() {
68 | // in order to be alike to `Map` `keys()` and `values()` are essentially the same thing for a `Set`.
69 | it("`keys()`", function() {
70 | const allKeys = set.keys();
71 | assert.deepEqual([...allKeys], api);
72 | });
73 |
74 | it("`values()`", function() {
75 | const allValues = set.values();
76 | assert.deepEqual([...allValues], api);
77 | });
78 |
79 | it("`[Symbol.iterator]()`", function() {
80 | const iteratorKey = Symbol.iterator;
81 | assert.deepEqual([...set[iteratorKey]()], api);
82 | });
83 | });
84 | });
85 |
--------------------------------------------------------------------------------
/test/es6katas/66-ObjectLiteralGetterTest.js:
--------------------------------------------------------------------------------
1 | // 66: object-literal - getter
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("An object literal can also contain getters", () => {
5 | it("just prefix the property with `get` (and make it a function)", function() {
6 | const obj = {
7 | get x() {
8 | return "ax";
9 | }
10 | };
11 |
12 | assert.equal(obj.x, "ax");
13 | });
14 |
15 | it("must have NO parameters", function() {
16 | const obj = {
17 | get x() {
18 | return "ax";
19 | }
20 | };
21 |
22 | assert.equal(obj.x, "ax");
23 | });
24 |
25 | it("can be a computed property (an expression enclosed in `[]`)", function() {
26 | const keyName = "x";
27 | const obj = {
28 | get [keyName]() {
29 | return "ax";
30 | }
31 | };
32 |
33 | assert.equal(obj.x, "ax");
34 | });
35 |
36 | it("can be removed using delete", function() {
37 | const obj = {
38 | get x() {
39 | return "ax";
40 | }
41 | };
42 | delete obj.x;
43 | assert.equal(obj.x, void 0);
44 | });
45 |
46 | // The following dont seem to work in the current transpiler version
47 | // but should be correct, as stated here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
48 | // It might be corrected later, new knowledge welcome.
49 |
50 | //it('must not overlap with a pure property', function() {
51 | // const obj = {
52 | // x: 1,
53 | // get x() { return 'ax'; }
54 | // };
55 | //
56 | // assert.equal(obj.x, 'ax');
57 | //});
58 | //
59 | //it('multiple `get` for the same property are not allowed', function() {
60 | // const obj = {
61 | // x: 1,
62 | // get x() { return 'ax'; },
63 | // get x() { return 'ax1'; }
64 | // };
65 | //
66 | // assert.equal(obj.x, 'ax');
67 | //});
68 | });
69 |
--------------------------------------------------------------------------------
/test/es6katas/67-ObjectLiteralTest.js:
--------------------------------------------------------------------------------
1 | // 67: object-literal - setter
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("An object literal can also contain setters", () => {
5 | describe("defining: a setter", function() {
6 | it("by prefixing the property with `set` (and make it a function)", function() {
7 | let theX = null;
8 | const obj = {
9 | set x(newX) {
10 | theX = newX;
11 | }
12 | };
13 |
14 | obj.x = "the new X";
15 | assert.equal(theX, "the new X");
16 | });
17 | it("must have exactly one parameter", function() {
18 | let setterCalledWith = void 0;
19 | const obj = {
20 | set x(newX) {
21 | if (arguments.length === 1) {
22 | setterCalledWith = arguments[0];
23 | }
24 | }
25 | };
26 |
27 | assert.equal((obj.x = "new value"), setterCalledWith);
28 | });
29 | it("can be a computed property (an expression enclosed in `[]`)", function() {
30 | const publicPropertyName = "x";
31 | const privatePropertyName = "_" + publicPropertyName;
32 | const obj = {
33 | [privatePropertyName]: "null",
34 | set [publicPropertyName](newValue) {
35 | this[privatePropertyName] = newValue;
36 | }
37 | };
38 |
39 | obj.x = "axe";
40 | assert.equal(obj._x, "axe");
41 | });
42 | });
43 |
44 | describe("working with/on the setter", function() {
45 | it("you can use `delete` to remove the property (including it`s setter)", function() {
46 | let setterCalled = false;
47 | const obj = {
48 | set x(param) {
49 | setterCalled = true;
50 | }
51 | };
52 |
53 | delete obj.x;
54 |
55 | obj.x = true;
56 | assert.equal(setterCalled, false);
57 | });
58 | });
59 |
60 | // TODO
61 | // The following dont seem to work in the current transpiler version
62 | // but should be correct, as stated here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set
63 | // It might be corrected later, new knowledge welcome.
64 | // it('must not overlap with a pure property', function() {
65 | // const obj = {
66 | // x: 1,
67 | // set x(val) { return 'ax'; }
68 | // };
69 | // assert.equal(obj.x, 'ax');
70 | // });
71 | // it('multiple `set` for the same property are not allowed', function() {
72 | // const obj = {
73 | // x: 1,
74 | // set x(v) { return 'ax'; },
75 | // set x(v) { return 'ax1'; }
76 | // };
77 | // assert.equal(obj.x, 'ax');
78 | // });
79 | });
80 |
--------------------------------------------------------------------------------
/test/es6katas/68-ReflectConstructTest.js:
--------------------------------------------------------------------------------
1 | // 68: Reflect - construct
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Reflect.construct` is the `new` operator as a function", function() {
5 | describe("the function itself", function() {
6 | it("is static on the `Reflect` object", function() {
7 | const name = "construct";
8 | assert.equal(name in Reflect, true);
9 | });
10 | it("is of type `function`", function() {
11 | const expectedType = "function";
12 | assert.equal(typeof Reflect.construct, expectedType);
13 | });
14 | });
15 |
16 | describe("the 1st parameter is the constructor to be invoked", function() {
17 | it("fails when given a number as constructor", function() {
18 | let aNumber = Number();
19 | assert.throws(() => {
20 | Reflect.construct(aNumber, []);
21 | }, TypeError);
22 | });
23 | it("works giving a function", function() {
24 | let aFunction = () => {};
25 | assert.doesNotThrow(() => {
26 | Reflect.construct(aFunction, []);
27 | });
28 | });
29 | it("works giving a class", function() {
30 | const aClass = class {};
31 | assert.doesNotThrow(() => {
32 | Reflect.construct(aClass, []);
33 | });
34 | });
35 | });
36 |
37 | describe("the 2nd parameter is a list of arguments, that will be passed to the constructor", function() {
38 | const aClass = class {};
39 | it("fails when it`s not an array(-like), e.g. a number", function() {
40 | let aNumber = Number();
41 | assert.throws(() => {
42 | Reflect.construct(aClass, aNumber);
43 | }, TypeError);
44 | });
45 | it("works with an array-like object (the `length` property look up should not throw)", function() {
46 | let arrayLike = { get length() {} };
47 | assert.doesNotThrow(() => {
48 | Reflect.construct(aClass, arrayLike);
49 | });
50 | });
51 | it("works with a real array", function() {
52 | let realArray = [];
53 | assert.doesNotThrow(() => {
54 | Reflect.construct(aClass, realArray);
55 | });
56 | });
57 | });
58 |
59 | describe("in use", function() {
60 | it("giving it a class it returns an instance of this class", function() {
61 | class Constructable {}
62 | let instance = Reflect.construct(Constructable, []);
63 |
64 | assert.equal(instance instanceof Constructable, true);
65 | });
66 |
67 | describe("the list of arguments are passed to the constructor as given", function() {
68 | class Constructable {
69 | constructor(...args) {
70 | this.args = args;
71 | }
72 | }
73 | it("if none given, nothing is passed", function() {
74 | let instance = Reflect.construct(Constructable, []);
75 |
76 | assert.deepEqual(instance.args, []);
77 | });
78 | it("passing an array, all args of any type are passed", function() {
79 | const argumentsList = ["arg1", ["arg2.1", "arg2.2"], { arg: 3 }];
80 | let instance = Reflect.construct(Constructable, argumentsList);
81 |
82 | assert.deepEqual(instance.args, argumentsList);
83 | });
84 | });
85 | });
86 |
87 | describe("the length property", function() {
88 | it("of `Reflect.construct` is 2", function() {
89 | let expected = 2;
90 | assert.equal(Reflect.construct.length, expected);
91 | });
92 | });
93 | });
94 |
--------------------------------------------------------------------------------
/test/es6katas/69-ReflectDefinePropertyTest.js:
--------------------------------------------------------------------------------
1 | // 69: Reflect - defineProperty
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Reflect.defineProperty()` is like `Object.defineProperty()` but returns a Boolean.", function() {
5 | describe("the function itself", function() {
6 | it("is static on the `Reflect` object", function() {
7 | const name = "defineProperty";
8 | assert.equal(name in Reflect, true);
9 | });
10 | it("is of type `function`", function() {
11 | const expectedType = "function";
12 | assert.equal(typeof Reflect.defineProperty, expectedType);
13 | });
14 | });
15 |
16 | describe("the 1st parameter is the object on which to define a property", function() {
17 | it("fails if it is not an object", function() {
18 | let noObj;
19 | assert.throws(() => {
20 | Reflect.defineProperty(noObj, "property", { value: "value" });
21 | }, TypeError);
22 | });
23 | it("accepts an object", function() {
24 | let obj = {};
25 | assert.doesNotThrow(() => {
26 | Reflect.defineProperty(obj, "property", { value: "value" });
27 | });
28 | });
29 | it("accepts an instance (of a class)", function() {
30 | let instance = new class {}();
31 | assert.doesNotThrow(() => {
32 | Reflect.defineProperty(instance, "property", { value: "value" });
33 | });
34 | });
35 | });
36 |
37 | describe("2nd parameter is the name of the property to be defined on the object (normally a string)", function() {
38 | it("works with a `normal` string", function() {
39 | let obj = {};
40 | Reflect.defineProperty(obj, "prop", {});
41 | assert.equal("prop" in obj, true);
42 | });
43 | it("a number gets converted into a string", function() {
44 | let obj = {};
45 | Reflect.defineProperty(obj, 1, {});
46 | assert.equal("1" in obj, true);
47 | });
48 | it("`undefined` also gets converted into a string (watch out!)", function() {
49 | let obj = {};
50 | let undef = void 0;
51 | Reflect.defineProperty(obj, undef, {});
52 | assert.equal("undefined" in obj, true);
53 | });
54 | it("it can be a symbol", function() {
55 | let obj = {};
56 | const sym = Symbol.for("prop");
57 | Reflect.defineProperty(obj, sym, {});
58 | assert.equal(sym in obj, true);
59 | });
60 | });
61 |
62 | describe("the `value` is part of the 3rd parameter, given as a property in an object `{value: ...}`", function() {
63 | // The entire complexity of the 3rd parameter might be covered in a later kata.
64 |
65 | it("contains the initial value of the property, as an object in the property `value`", function() {
66 | let obj = {};
67 | Reflect.defineProperty(obj, "prop", { value: "property value" });
68 | assert.equal(obj.prop, "property value");
69 | });
70 | it("can be of any type (even itself)", function() {
71 | let obj = {};
72 | Reflect.defineProperty(obj, "prop", { value: obj });
73 | assert.equal(obj.prop, obj);
74 | });
75 | });
76 |
77 | describe("the return value of the function indicates wether the property was defined successfully", function() {
78 | describe("returns true", function() {
79 | it("when the property was created (which requires the 3rd parameter too!!!)", function() {
80 | let instance = new class {}();
81 | const wasPropertyDefined = Reflect.defineProperty(instance, void 0, {
82 | value: true
83 | });
84 | assert.equal(wasPropertyDefined, true);
85 | });
86 | it("no matter what the value of the property is (just the 3rd param has to exist as `{}`)", function() {
87 | let instance = new class {}();
88 | const wasPropertyDefined = Reflect.defineProperty(instance, void 0, {});
89 | assert.equal(wasPropertyDefined, true);
90 | });
91 | });
92 | });
93 | });
94 |
--------------------------------------------------------------------------------
/test/es6katas/7-BlockScopeLetTest.js:
--------------------------------------------------------------------------------
1 | // 7: block scope - let
2 | // To do: make all tests pass, leave the asserts unchanged!
3 |
4 | describe("`let` restricts the scope of the variable to the current block", () => {
5 | describe("`let` vs. `var`", () => {
6 | it("`var` works as usual", () => {
7 | var varX = false;
8 | if (true) { // eslint-disable-line
9 | var varX = true; // eslint-disable-line
10 | }
11 | assert.equal(varX, true);
12 | });
13 |
14 | it("`let` restricts scope to inside the block", () => {
15 | if (true) { // eslint-disable-line
16 | let letX = true; // eslint-disable-line
17 | }
18 | assert.throws(() => console.log(letX)); // eslint-disable-line
19 | });
20 | });
21 |
22 | describe("`let` usage", () => {
23 | it("`let` use in `for` loops", () => {
24 | let obj = { x: 1 };
25 | for (let key in obj) { // eslint-disable-line
26 | }
27 | assert.throws(() => console.log(key)); // eslint-disable-line
28 | });
29 |
30 | it("create artifical scope, using curly braces", () => {
31 | {
32 | let letX = true; // eslint-disable-line
33 | }
34 | assert.throws(() => console.log(letX)); // eslint-disable-line
35 | });
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/test/es6katas/70-SetClearTest.js:
--------------------------------------------------------------------------------
1 | // 70: Set - clear
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`clear()` removes all elements from a Set object.", function() {
5 | let set;
6 | beforeEach(() => (set = new Set()));
7 |
8 | it("`set.size` becomes 0", function() {
9 | set.add("one").add(2);
10 | set.clear();
11 |
12 | const expectedSize = 0;
13 | assert.equal(set.size, expectedSize);
14 | });
15 |
16 | it("the iterator `set.entries()` will not contain any items", function() {
17 | set.add("one").add(2);
18 |
19 | set.clear();
20 |
21 | const { done } = set.entries().next();
22 | assert.equal(done, true);
23 | });
24 |
25 | it("any call to `set.has()` returns false", function() {
26 | set.add("one").add(2);
27 |
28 | set.clear();
29 |
30 | assert.deepEqual(set.has(2), false);
31 | });
32 |
33 | it("returns `undefined`", function() {
34 | var expectedReturn = void 0;
35 | assert.equal(set.clear(), expectedReturn);
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/test/es6katas/71-StringRepeatTest.js:
--------------------------------------------------------------------------------
1 | // 71: String - `repeat()`
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`str.repeat(x)` appends `x` copies of `str` to each other and returns it", function() {
5 | describe("pass the count to `str.repeat(count)`", function() {
6 | it("for `1` the string stays the same", function() {
7 | const what = "one".repeat(1);
8 | assert.equal(what, "one");
9 | });
10 | it("for `3` the string `x` becomes `xxx`", function() {
11 | const actual = "x".repeat(3);
12 | assert.equal(actual, "xxx");
13 | });
14 | it("for `0` an empty string is returned", function() {
15 | const dontRepeat = 0;
16 | assert.equal("shrink".repeat(dontRepeat), "");
17 | });
18 |
19 | it('the count is not an int, such as "3", it gets coerced to an int', function() {
20 | const repeated = "three".repeat("3");
21 | assert.equal(repeated, "threethreethree");
22 | });
23 | });
24 |
25 | describe("throws an error for", function() {
26 | it("a count of <0", function() {
27 | const belowZero = -1;
28 | assert.throws(() => {
29 | "".repeat(belowZero);
30 | }, RangeError);
31 | });
32 | it("a count of +Infinty", function() {
33 | let infinity = Infinity;
34 | assert.throws(() => {
35 | "".repeat(infinity);
36 | }, RangeError);
37 | });
38 | });
39 |
40 | describe("accepts everything that can be coerced to a string", function() {
41 | it("e.g. a boolean", function() {
42 | let aBool = false;
43 | assert.equal(String.prototype.repeat.call(aBool, 2), "falsefalse");
44 | });
45 | it("e.g. a number", function() {
46 | let aNumber = "1";
47 | assert.equal(String.prototype.repeat.call(aNumber, 2), "11");
48 | });
49 | });
50 |
51 | describe("for my own (string) class", function() {
52 | it("calls `toString()` to make it a string", function() {
53 | class MyString {
54 | toString() {
55 | return "my string";
56 | }
57 | }
58 |
59 | const expectedString = "my string";
60 |
61 | assert.equal(String(new MyString()).repeat(1), expectedString);
62 | });
63 | it("`toString()` is only called once", function() {
64 | let counter = 1;
65 | class X {
66 | toString() {
67 | return counter++;
68 | }
69 | }
70 |
71 | let repeated = String(new X()).repeat(2);
72 |
73 | assert.equal(repeated, "11");
74 | });
75 | });
76 | });
77 |
--------------------------------------------------------------------------------
/test/es6katas/72-StringStrtsWithTest.js:
--------------------------------------------------------------------------------
1 | // 72: String - `startsWith()`
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`str.startsWith(searchString)` determines whether `str` begins with `searchString`.", function() {
5 | const s = "the string s";
6 |
7 | describe("1st parameter, the string to search for", function() {
8 | it("works with just a character", function() {
9 | const actual = s.startsWith("t");
10 | assert.equal(actual, true);
11 | });
12 | it("works with a string", function() {
13 | const expected = true;
14 | assert.equal(s.startsWith("the"), expected);
15 | });
16 | it("works with unicode characters", function() {
17 | const nuclear = "☢ NO";
18 | assert.equal(nuclear.startsWith("☢"), true);
19 | });
20 | it("a regular expression throws a TypeError", function() {
21 | const aRegExp = /./;
22 | assert.throws(() => {
23 | "".startsWith(aRegExp);
24 | }, TypeError);
25 | });
26 | });
27 |
28 | describe("2nd parameter, the position where to start searching from", function() {
29 | it('find "str" at position 4', function() {
30 | const position = 4;
31 | assert.equal(s.startsWith("str", position), true);
32 | });
33 | it("`undefined` is the same as 0", function() {
34 | const _undefined_ = "0";
35 | assert.equal(s.startsWith("the", _undefined_), true);
36 | });
37 | it("the parameter gets coerced to an int", function() {
38 | const position = "4";
39 | assert.equal(s.startsWith("str", position), true);
40 | });
41 | it("a value larger than the string`s length, returns false", function() {
42 | const expected = false;
43 | assert.equal(s.startsWith(" ", s.length + 1), expected);
44 | });
45 | });
46 |
47 | describe("transfer the functionality to other objects", function() {
48 | const startsWith = (...args) => String.prototype.startsWith.call(...args);
49 |
50 | it("e.g. a boolean", function() {
51 | let aBool = true;
52 | assert.equal(startsWith(!aBool, "false"), true);
53 | });
54 | it("e.g. a number", function() {
55 | let aNumber = 1900;
56 | assert.equal(startsWith(aNumber + 84, "1984"), true);
57 | });
58 | it("also using the position works", function() {
59 | const position = 1;
60 | assert.equal(startsWith(1994, "99", position), true);
61 | });
62 | });
63 | });
64 |
--------------------------------------------------------------------------------
/test/es6katas/74-StringEndsWithTest.js:
--------------------------------------------------------------------------------
1 | // 74: String - `endsWith()`
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`str.endsWith(searchString)` determines whether `str` ends with `searchString`.", function() {
5 | const s = "el fin";
6 |
7 | describe("1st parameter, the string to search for", function() {
8 | it("works with just a character", function() {
9 | const doesEndWith = s.endsWith("n");
10 | assert.equal(doesEndWith, true);
11 | });
12 | it("works with a string", function() {
13 | const expected = true;
14 | assert.equal(s.endsWith("fin"), expected);
15 | });
16 | it("works with unicode characters", function() {
17 | const nuclear = "NO ☢";
18 | assert.equal(nuclear.endsWith("☢"), true);
19 | });
20 | it("a regular expression throws a TypeError", function() {
21 | const aRegExp = /the/;
22 | assert.throws(() => {
23 | "".endsWith(aRegExp);
24 | }, TypeError);
25 | });
26 | });
27 |
28 | describe("2nd parameter, searches within this string as if this string were only this long", function() {
29 | it('find "el" at a substring of the length 2', function() {
30 | const endPos = 2;
31 | assert.equal(s.endsWith("el", endPos), true);
32 | });
33 | it("`undefined` uses the entire string", function() {
34 | const _undefined_ = void 0;
35 | assert.equal(s.endsWith("fin", _undefined_), true);
36 | });
37 | it("the parameter gets coerced to an int", function() {
38 | const position = "5";
39 | assert.equal(s.endsWith("fi", position), true);
40 | });
41 | describe("value less than 0", function() {
42 | it("returns `true`, when searching for an empty string", function() {
43 | const emptyString = "";
44 | assert.equal("1".endsWith(emptyString, -1), true);
45 | });
46 | it("return `false`, when searching for a non-empty string", function() {
47 | const notEmpty = "not-empty string";
48 | assert.equal("1".endsWith(notEmpty, -1), false);
49 | });
50 | });
51 | });
52 |
53 | describe("transfer the functionality to other objects", function() {
54 | const endsWith = (...args) => String.prototype.endsWith.call(...args);
55 |
56 | it("e.g. a boolean", function() {
57 | let aBool = true;
58 | assert.equal(endsWith(!aBool, "lse"), true);
59 | });
60 | it("e.g. a number", function() {
61 | let aNumber = 84;
62 | assert.equal(endsWith(aNumber + 1900, 84), true);
63 | });
64 | it("also using the position works", function() {
65 | const position = 3;
66 | assert.equal(endsWith(1994, "99", position), true);
67 | });
68 | });
69 | });
70 |
--------------------------------------------------------------------------------
/test/es6katas/76-PromiseCreationTest.js:
--------------------------------------------------------------------------------
1 | // 76: Promise - creation
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("a promise can be created in multiple ways", function() {
5 | describe("creating a promise fails when", function() {
6 | it("using `Promise` as a function", function() {
7 | function callPromiseAsFunction() {
8 | return new Promise();
9 | }
10 | assert.throws(callPromiseAsFunction);
11 | });
12 |
13 | it("no parameter is passed", function() {
14 | function promiseWithoutParams() {
15 | new Promise();
16 | }
17 | assert.throws(promiseWithoutParams);
18 | });
19 |
20 | it("passing a non-callable throws too", function() {
21 | const notAFunction = 1;
22 | assert.throws(() => {
23 | new Promise(notAFunction);
24 | });
25 | });
26 | });
27 |
28 | describe("most commonly Promises get created using the constructor", function() {
29 | it("by passing a resolve function to it", function() {
30 | const promise = new Promise(resolve => resolve());
31 | return promise;
32 | });
33 |
34 | it("by passing a resolve and a reject function to it", function(done) {
35 | const promise = new Promise((resolve, reject) => reject());
36 |
37 | promise
38 | .then(() => done(new Error("Expected promise to be rejected.")))
39 | .catch(done);
40 | });
41 | });
42 |
43 | describe("`Promise.all()` returns a promise that resolves when all given promises resolve", function() {
44 | it("returns all results", function(done) {
45 | const promise = Promise.all([
46 | new Promise(resolve => resolve(1)),
47 | new Promise(resolve => resolve(2))
48 | ]);
49 |
50 | promise
51 | .then(value => {
52 | assert.deepEqual(value, [1, 2]);
53 | done();
54 | })
55 | .catch(e => done(new Error(e)));
56 | });
57 |
58 | it("is rejected if one rejects", function(done) {
59 | const promise = Promise.all([new Promise((resolve, reject) => reject())]);
60 |
61 | promise.then(() => done(new NotRejectedError())).catch(() => done());
62 | });
63 | });
64 |
65 | describe("`Promise.race()` returns the first settled promise", function() {
66 | it("if it resolves first, the promises resolves", function(done) {
67 | const earlyResolvingPromise = new Promise(resolve => resolve("1st :)"));
68 | const promise = Promise.race([earlyResolvingPromise]);
69 |
70 | promise
71 | .then(value => {
72 | assert.deepEqual(value, "1st :)");
73 | done();
74 | })
75 | .catch(e =>
76 | done(new Error("Expected to resolve, but failed with: " + e))
77 | );
78 | });
79 |
80 | it("if one of the given promises rejects first, the returned promise is rejected", function(
81 | done
82 | ) {
83 | const earlyRejectedPromise = new Promise((resolve, reject) =>
84 | reject("I am a rejector")
85 | );
86 | const lateResolvingPromise = new Promise(resolve =>
87 | setTimeout(resolve, 10)
88 | );
89 | const promise = Promise.race([
90 | earlyRejectedPromise,
91 | lateResolvingPromise
92 | ]);
93 |
94 | promise
95 | .then(() => done(new NotRejectedError()))
96 | .catch(value => {
97 | assert.equal(value, "I am a rejector");
98 | done();
99 | })
100 | .catch(done);
101 | });
102 | });
103 |
104 | describe("`Promise.resolve()` returns a resolving promise", function() {
105 | it("if no value given, it resolves with `undefined`", function(done) {
106 | const promise = Promise.resolve();
107 |
108 | promise
109 | .then(value => {
110 | assert.deepEqual(value, void 0);
111 | done();
112 | })
113 | .catch(e =>
114 | done(new Error("Expected to resolve, but failed with: " + e))
115 | );
116 | });
117 |
118 | it("resolves with the given value", function(done) {
119 | const promise = Promise.resolve("quick resolve");
120 |
121 | promise
122 | .then(value => {
123 | assert.equal(value, "quick resolve");
124 | done();
125 | })
126 | .catch(e => done(e));
127 | });
128 | });
129 |
130 | describe("`Promise.reject()` returns a rejecting promise", function() {
131 | it("if no value given, it rejects with `undefined`", function(done) {
132 | const promise = Promise.reject();
133 |
134 | promise
135 | .then(() => done(new NotRejectedError()))
136 | .catch(value => {
137 | assert.deepEqual(value, void 0);
138 | done();
139 | })
140 | .catch(done);
141 | });
142 |
143 | it("the parameter passed to `reject()` can be used in the `.catch()`", function(
144 | done
145 | ) {
146 | const promise = Promise.reject("quick reject");
147 |
148 | promise
149 | .then(() => done(new NotRejectedError()))
150 | .catch(value => {
151 | assert.deepEqual(value, "quick reject");
152 | done();
153 | })
154 | .catch(done);
155 | });
156 | });
157 | });
158 |
159 | class NotRejectedError extends Error {
160 | constructor() {
161 | super();
162 | this.message = "Expected promise to be rejected.";
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/test/es6katas/77-PromiseChainingTest.js:
--------------------------------------------------------------------------------
1 | // 77: Promise - chaining
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("chaining multiple promises can enhance readability", () => {
5 | describe("prerequisites for understanding", function() {
6 | it("reminder: the test passes when a fulfilled promise is returned", function() {
7 | return Promise.resolve("I should fulfill.");
8 | });
9 |
10 | it("a function given to `then()` fulfills (if it doesnt throw)", function() {
11 | const beNice = () => {
12 | return "I am nice";
13 | };
14 | return Promise.resolve()
15 | .then(beNice)
16 | .then(niceMessage => assert.equal(niceMessage, "I am nice"));
17 | });
18 | });
19 |
20 | describe("chain promises", function() {
21 | const removeMultipleSpaces = string => string.replace(/\s+/g, " ");
22 |
23 | it("`then()` receives the result of the promise it was called on", function() {
24 | const wordsPromise = Promise.resolve(
25 | "one space between each word"
26 | );
27 | return wordsPromise
28 | .then(string => removeMultipleSpaces(string))
29 | .then(actual => {
30 | assert.equal(actual, "one space between each word");
31 | });
32 | });
33 |
34 | const appendPeriod = string => `${string}.`;
35 |
36 | it("multiple `then()`s can be chained", function() {
37 | const wordsPromise = Promise.resolve("Sentence without an end");
38 | return wordsPromise.then(s => removeMultipleSpaces(s)).then(actual => {
39 | assert.equal(actual, "Sentence without an end");
40 | });
41 | });
42 |
43 | const trim = string => string.replace(/^\s+/, "").replace(/\s+$/, "");
44 |
45 | it("order of the `then()`s matters", function() {
46 | const wordsPromise = Promise.resolve("Sentence without an end ");
47 | return wordsPromise
48 | .then(removeMultipleSpaces)
49 | .then(trim)
50 | .then(actual => {
51 | assert.equal(actual, "Sentence without an end");
52 | });
53 | });
54 |
55 | const asyncUpperCaseStart = (string, onDone) => {
56 | const format = () => onDone(string[0].toUpperCase() + string.substr(1));
57 | setTimeout(format, 100);
58 | };
59 |
60 | it("any of the things given to `then()` can resolve asynchronously (the real power of Promises)", function() {
61 | const wordsPromise = Promise.resolve("sentence without an end");
62 | wordsPromise
63 | .then(string => new Promise(resolve => asyncUpperCaseStart)) // eslint-disable-line
64 | .then(
65 | string =>
66 | new Promise(resolve =>
67 | setTimeout(() => resolve(appendPeriod(string)), 100)
68 | )
69 | )
70 | .then(actual => {
71 | assert.equal(actual, "Sentence without an end.");
72 | });
73 | });
74 |
75 | it("also asynchronously, the order still matters, promises wait, but don`t block", function() {
76 | const wordsPromise = Promise.resolve("trailing space ");
77 | wordsPromise
78 | .then(
79 | string => new Promise(resolve => asyncUpperCaseStart(string, resolve))
80 | )
81 | .then(
82 | string =>
83 | new Promise(resolve =>
84 | setTimeout(() => resolve(appendPeriod(string)), 100)
85 | )
86 | )
87 | .then(
88 | string =>
89 | new Promise(resolve => setTimeout(() => resolve(trim(string)), 100))
90 | )
91 | .then(actual => {
92 | assert.equal(actual, "Trailing space.");
93 | });
94 | });
95 | });
96 | });
97 |
--------------------------------------------------------------------------------
/test/es6katas/78-PromiseApiOverviewTest.js:
--------------------------------------------------------------------------------
1 | // 78: Promise - API overview
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("`Promise` API overview", function() {
5 | it("`new Promise()` requires a function as param", () => {
6 | const param = () => {};
7 | assert.doesNotThrow(() => {
8 | new Promise(param);
9 | });
10 | });
11 |
12 | describe("resolving a promise", () => {
13 | // reminder: the test passes when a fulfilled promise is returned
14 | it("via constructor parameter `new Promise((resolve) => { resolve(); })`", () => {
15 | const param = resolve => {
16 | resolve();
17 | };
18 | return new Promise(param);
19 | });
20 | it("using `Promise.resolve()`", () => {
21 | return Promise.resolve("all fine");
22 | });
23 | });
24 |
25 | describe("a rejected promise", () => {
26 | it("using the constructor parameter", done => {
27 | const promise = new Promise((resolve, reject) => {
28 | reject();
29 | });
30 | promise
31 | .then(() => done(new Error("The promise is expected to be rejected.")))
32 | .catch(() => done());
33 | });
34 | it("via `Promise.reject()`", done => {
35 | const promise = Promise.reject();
36 | promise
37 | .then(() => done(new Error("The promise is expected to be rejected.")))
38 | .catch(() => done());
39 | });
40 | });
41 |
42 | const resolvingPromise = Promise.resolve();
43 | const rejectingPromise = Promise.reject();
44 |
45 | describe("`Promise.all()`", () => {
46 | it("`Promise.all([p1, p2])` resolves when all promises resolve", () =>
47 | Promise.all([resolvingPromise, resolvingPromise]));
48 | it("`Promise.all([p1, p2])` rejects when a promise is rejected", done => {
49 | Promise.all([rejectingPromise])
50 | .then(() => done(new Error("The promise is expected to be rejected.")))
51 | .catch(() => done());
52 | });
53 | });
54 |
55 | describe("`Promise.race()`", () => {
56 | it("`Promise.race([p1, p2])` resolves when one of the promises resolves", () =>
57 | Promise.race([resolvingPromise, resolvingPromise]));
58 | it("`Promise.race([p1, p2])` rejects when one of the promises rejects", done => {
59 | Promise.race([rejectingPromise, resolvingPromise])
60 | .then(() => done(new Error("The promise is expected to be rejected.")))
61 | .catch(() => done());
62 | });
63 | it("`Promise.race([p1, p2])` order matters (and timing)", () =>
64 | Promise.race([resolvingPromise, rejectingPromise]));
65 | });
66 | });
67 |
--------------------------------------------------------------------------------
/test/es6katas/79-PromiseCatchTest.js:
--------------------------------------------------------------------------------
1 | // 79: Promise - catch
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 | // Here we use promises to trigger, don't modify the block with the
4 | // returning promise!
5 |
6 | describe("`catch()` returns a Promise and deals with rejected cases only", () => {
7 | describe("prerequisites for understanding", () => {
8 | it("*return* a fulfilled promise, to pass a test", done => {
9 | Promise.resolve();
10 | done();
11 | assert(false); // Don't touch! Make the test pass in the line above!
12 | });
13 |
14 | it("reminder: the test passes when a fulfilled promise is returned", () => {
15 | return Promise.resolve("I should fulfill.");
16 | });
17 | });
18 |
19 | describe("`catch` method basics", () => {
20 | it("is an instance method", () => {
21 | const p = Promise.resolve();
22 | assert.equal(typeof p.catch, "function");
23 | });
24 |
25 | it("catches only promise rejections", done => {
26 | const promise = Promise.reject();
27 | promise
28 | .then(() => {
29 | done("Should not be called!");
30 | })
31 | .catch(done);
32 | });
33 |
34 | it("returns a new promise", () => {
35 | const whatToReturn = () => Promise.resolve();
36 | const promise = Promise.reject();
37 | return promise.catch(() => whatToReturn());
38 | });
39 |
40 | it("converts it`s return value into a promise", () => {
41 | const p = Promise.resolve("promise?");
42 | const p1 = p.catch(() => void 0);
43 |
44 | return p1.then(result => assert.equal("promise?", result));
45 | });
46 |
47 | it("the first parameter is the rejection reason", () => {
48 | const p = Promise.reject("oops");
49 |
50 | return p.catch(reason => {
51 | assert.equal(reason, "oops");
52 | });
53 | });
54 | });
55 |
56 | describe("multiple `catch`es", () => {
57 | it("only the first `catch` is called", () => {
58 | const p = Promise.reject("1");
59 | const p1 = p
60 | .catch(reason => `${reason} AND 2`)
61 | .catch(reason => `${reason} AND 3`);
62 |
63 | return p1.then(result => assert.equal(result, "1 AND 2"));
64 | });
65 |
66 | it("if a `catch` throws, the next `catch` catches it", () => {
67 | const p = Promise.reject("1");
68 | const p1 = p
69 | .catch(reason => {
70 | throw Error(`${reason} AND 2`);
71 | })
72 | .catch(err => {
73 | throw Error(`${err.message} AND 3`);
74 | })
75 | .catch(err => err.message);
76 |
77 | return p1.then(result => assert.equal(result, "1 AND 2 AND 3"));
78 | });
79 | });
80 | });
81 |
--------------------------------------------------------------------------------
/test/es6katas/8-BlockScopeConstTest.js:
--------------------------------------------------------------------------------
1 | // 8: block scope - const
2 | // To do: make all tests pass, leave the asserts unchanged!
3 |
4 | describe("`const` is like `let` plus read-only", () => {
5 | describe("scalar values are read-only", () => {
6 | it("number", () => {
7 | const constNum = 0;
8 | //constNum = 1; This is going to crash
9 | assert.equal(constNum, 0);
10 | });
11 |
12 | it("string", () => {
13 | const constString = "I am a const";
14 | //constString = "Cant change you?"; This is going to crash
15 | assert.equal(constString, "I am a const");
16 | });
17 | });
18 |
19 | const notChangeable = 23;
20 |
21 | it("const scope leaks too", () => {
22 | assert.equal(notChangeable, 23);
23 | });
24 |
25 | describe("complex types are NOT fully read-only", () => {
26 | it("array", () => {
27 | const arr = [42, 23];
28 | arr[0] = 0;
29 | assert.equal(arr[0], 0);
30 | });
31 |
32 | it("object", () => {
33 | const obj = { x: 1 };
34 | obj.x = 2;
35 | assert.equal(obj.x, 2);
36 | });
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/test/es6katas/9-ObjectLiteralsBasicsTest.js:
--------------------------------------------------------------------------------
1 | // 9: object-literals - basics
2 | // To do: make all tests pass, leave the assert lines unchanged!
3 |
4 | describe("The object literal allows for new shorthands", () => {
5 | const x = 1;
6 | const y = 2;
7 |
8 | describe("with variables", () => {
9 | it("the short version for `{x: x}` is {x}", () => {
10 | const short = { y };
11 | assert.deepEqual(short, { y: y });
12 | });
13 | it("works with multiple variables too", () => {
14 | const short = { x, y };
15 | assert.deepEqual(short, { x: x, y: y });
16 | });
17 | });
18 |
19 | describe("with methods", () => {
20 | const func = () => func;
21 |
22 | it("using the name only uses it as key", () => {
23 | const short = { func };
24 | assert.deepEqual(short, { func: func });
25 | });
26 |
27 | it("a different key must be given explicitly, just like before ES6", () => {
28 | const short = { otherKey: func };
29 | assert.deepEqual(short, { otherKey: func });
30 | });
31 |
32 | it("inline functions, can written as `obj={func(){}}` instead of `obj={func:function(){}}`", () => {
33 | const short = {
34 | inlineFunc() {
35 | return "I am inline";
36 | }
37 | };
38 | assert.deepEqual(short.inlineFunc(), "I am inline");
39 | });
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/test/fibonacci/fibonacci.spec.js:
--------------------------------------------------------------------------------
1 | import { fibonacci, fibonacciTailRec } from "../../src/fibonacci/fibonacci";
2 |
3 | describe("Fibonacci spec", () => {
4 | jsc.property(
5 | "every fibonacci element can be expressed as the sum of the two previous items",
6 | arbitrarySmallPositiveInteger(),
7 | n => {
8 | const x = fibonacci(n);
9 | const y = fibonacci(n - 1);
10 | const z = fibonacci(n - 2);
11 | return x === y + z;
12 | }
13 | );
14 |
15 | jsc.property(
16 | "fibonacci tail recursive version returns the same value the regular one does",
17 | arbitrarySmallPositiveInteger(),
18 | n => {
19 | return fibonacciTailRec(n) === fibonacci(n);
20 | }
21 | );
22 |
23 | jsc.property(
24 | "tail recursive implementation should support bigger numbers",
25 | arbitraryPositiveInteger(),
26 | n => {
27 | const x = fibonacciTailRec(n);
28 | const y = fibonacciTailRec(n - 1);
29 | const z = fibonacciTailRec(n - 2);
30 | return x === y + z;
31 | }
32 | );
33 |
34 | function arbitrarySmallPositiveInteger() {
35 | return jsc.integer(2, 20);
36 | }
37 |
38 | function arbitraryPositiveInteger() {
39 | return jsc.integer(2, 2000);
40 | }
41 | });
42 |
--------------------------------------------------------------------------------
/test/find-the-right-triangle/find-the-right-triangle.spec.js:
--------------------------------------------------------------------------------
1 | import findTheRightTriangles from "../../src/find-the-rigth-triangle/find-the-right-triangle";
2 |
3 | describe("Find the right triangle spec", () => {
4 | it("returns a non empty array because right triangles exist", () => {
5 | const triangles = findTheRightTriangles();
6 |
7 | expect(triangles).to.not.have.lengthOf(0);
8 | });
9 |
10 | it("every side of each triangle is less than or equal to 10", () => {
11 | const triangles = findTheRightTriangles();
12 |
13 | expect(
14 | triangles.every(
15 | triangle => triangle[0] <= 10 && triangle[1] <= 10 && triangle[2] <= 10
16 | )
17 | ).to.equal(true);
18 | });
19 |
20 | it("the perimeter of every triangle is equal to 24", () => {
21 | const triangles = findTheRightTriangles();
22 |
23 | expect(
24 | triangles.every(
25 | triangle => triangle[0] + triangle[1] + triangle[2] === 24
26 | )
27 | ).to.equal(true);
28 | });
29 |
30 | it("every triangle is a right triangle", () => {
31 | const triangles = findTheRightTriangles();
32 |
33 | expect(
34 | triangles.every(
35 | triangle =>
36 | Math.pow(triangle[0], 2) + Math.pow(triangle[1], 2) ===
37 | Math.pow(triangle[2], 2)
38 | )
39 | ).to.equal(true);
40 | });
41 | });
42 |
--------------------------------------------------------------------------------
/test/fizz-buzz/fizz-buzz.spec.js:
--------------------------------------------------------------------------------
1 | import fizzBuzz from "../../src/fizz-buzz/fizz-buzz";
2 |
3 | describe("FizzBuzz spec", () => {
4 | it("should return the value passed as String if it's not multiple of 3 or 5", () => {
5 | const result = fizzBuzz(1);
6 |
7 | expect(result).to.equal("1");
8 | });
9 |
10 | it("should return Fizz if the value passed is multiple of three", () => {
11 | const result = fizzBuzz(3);
12 |
13 | expect(result).to.equal("Fizz");
14 | });
15 |
16 | it("should return Buzz if the value passed is multiple of five", () => {
17 | const result = fizzBuzz(5);
18 |
19 | expect(result).to.equal("Buzz");
20 | });
21 |
22 | it("should return FizzBUzz if the value passed is multiple of three and five", () => {
23 | const result = fizzBuzz(15);
24 |
25 | expect(result).to.equal("FizzBuzz");
26 | });
27 |
28 | const arbitraryMultipleOfThree = jsc.suchthat(multipleOf(3), value => {
29 | return value % 3 == 0 && value % 5 != 0;
30 | });
31 | const arbitraryMultipleOfFive = jsc.suchthat(multipleOf(5), value => {
32 | return value % 5 == 0 && value % 3 != 0;
33 | });
34 | const arbitraryMultipleOfThreeAndFive = multipleOf(15);
35 |
36 | function multipleOf(x) {
37 | return jsc.integer.smap(value => Math.abs(value) * x);
38 | }
39 |
40 | function arbitraryNotMultipleOf(...values) {
41 | return jsc.suchthat(
42 | jsc.integer.smap(x => Math.abs(x)),
43 | value => values.filter(x => value % x == 0).length == 0
44 | );
45 | }
46 |
47 | jsc.property(
48 | "values not multiple of 3 or 5 should be returned as a string",
49 | arbitraryNotMultipleOf(3, 5),
50 | value => {
51 | return fizzBuzz(value) === value.toString();
52 | }
53 | );
54 |
55 | jsc.property(
56 | "values multiple of 3 should return Fizz",
57 | arbitraryMultipleOfThree,
58 | value => {
59 | return fizzBuzz(value) === "Fizz";
60 | }
61 | );
62 |
63 | jsc.property(
64 | "values multiple of 5 should return Buzz",
65 | arbitraryMultipleOfFive,
66 | value => {
67 | return fizzBuzz(value) === "Buzz";
68 | }
69 | );
70 |
71 | jsc.property(
72 | "values multiple of 3 and 5 should return FizzBuzz",
73 | arbitraryMultipleOfThreeAndFive,
74 | value => {
75 | return fizzBuzz(value) === "FizzBuzz";
76 | }
77 | );
78 | });
79 |
--------------------------------------------------------------------------------
/test/greeting/greeting.spec.js:
--------------------------------------------------------------------------------
1 | import { greet } from "../../src/greeting/greeting";
2 |
3 | describe("Greetings kata", () => {
4 | it("should say hello to bob if the name is bob", () => {
5 | expect(greet("Bob")).to.equal("Hello, Bob.");
6 | });
7 |
8 | it("should say hello to my friend if the input is not defined", () => {
9 | expect(greet()).to.equal("Hello, my friend.");
10 | });
11 |
12 | it("should say hello yelling to JERRY if he's yelling", () => {
13 | expect(greet("JERRY")).to.equal("HELLO JERRY!");
14 | });
15 |
16 | it("should say hello to every member in the group of two people if we greet more than one person", () => {
17 | expect(greet("Jill", "Jane")).to.equal("Hello, Jill and Jane.");
18 | });
19 |
20 | it("should say hello to my three friends using Oxford coma", () => {
21 | const result = greet("Amy", "Brian", "Charlotte");
22 | expect(result).to.equal("Hello, Amy, Brian, and Charlotte.");
23 | });
24 |
25 | it("should say hello to a group of friends when someone is yelling and some others not", () => {
26 | const result = greet("Amy", "BRIAN", "Charlotte");
27 | expect(result).to.equal("Hello, Amy and Charlotte. AND HELLO BRIAN!");
28 | });
29 |
30 | it("should split names containing , as two names", () => {
31 | const result = greet("Amy", "Brian", "Char,lotte");
32 | expect(result).to.equal("Hello, Amy, Brian, Char, and lotte.");
33 | });
34 |
35 | it('should handle names rounded with "" as a single name', () => {
36 | const result = greet("Bob", '"Charlie, Dianne"');
37 | expect(result).to.equal("Hello, Bob and Charlie, Dianne.");
38 | });
39 |
40 | jsc.property(
41 | "says hello using the name passed as parameter",
42 | arbitraryLowerCaseRegularName(),
43 | name => {
44 | return `Hello, ${name}.` === greet(name);
45 | }
46 | );
47 |
48 | jsc.property(
49 | "if the user of the lib is yelling, we should yell back",
50 | arbitraryLowerCaseRegularName().smap(name => name.toUpperCase()),
51 | name => {
52 | return `HELLO ${name}!` === greet(name);
53 | }
54 | );
55 |
56 | jsc.property(
57 | "should say hello to a bunch of people using Oxford coma",
58 | arbitraryListOfNamesGreaterThan(2),
59 | names => {
60 | const result = greet(...names);
61 | const containsOxfordComa = result.indexOf(", and") !== -1;
62 | const containsAsManyComasAsNames =
63 | result.split(", ").length - 1 === names.length;
64 | const containsEveryNameButTheLastOneFollowedByAComa = names
65 | .slice(0, -1)
66 | .every(name => result.indexOf(name + ", ") !== -1);
67 | return (
68 | containsOxfordComa &&
69 | containsAsManyComasAsNames &&
70 | containsEveryNameButTheLastOneFollowedByAComa
71 | );
72 | }
73 | );
74 |
75 | jsc.property(
76 | "the greet contains every name passed as parameter",
77 | jsc.nearray(arbitraryLowerCaseRegularName()),
78 | names => {
79 | const result = greet(...names);
80 | return names.every(name => result.indexOf(name) !== -1);
81 | }
82 | );
83 | });
84 |
85 | function arbitraryLowerCaseRegularName() {
86 | return jsc.suchthat(
87 | jsc.asciinestring,
88 | string =>
89 | `${string}`.toUpperCase() !== string &&
90 | string.indexOf(",") === -1 &&
91 | string.indexOf('"') === -1
92 | );
93 | }
94 |
95 | function arbitraryListOfNamesGreaterThan(minimumListSize) {
96 | return jsc.suchthat(
97 | jsc.nearray(arbitraryLowerCaseRegularName()),
98 | names => names.length > minimumListSize
99 | );
100 | }
101 |
--------------------------------------------------------------------------------
/test/maxibon/developer.spec.js:
--------------------------------------------------------------------------------
1 | import {
2 | Developer,
3 | Pedro,
4 | Fran,
5 | Davide,
6 | Sergio,
7 | Jorge
8 | } from "../../src/maxibon/maxibon";
9 |
10 | describe("Developer spec", () => {
11 | jsc.property(
12 | "developers can't grab a negative number of maxibons",
13 | jsc.string,
14 | jsc.integer,
15 | (name, maxibonsToGrab) => {
16 | const dev = new Developer(name, maxibonsToGrab);
17 | return dev.maxibonsToGrab >= 0;
18 | }
19 | );
20 |
21 | it("assign the number of maxibons specified to every developer", () => {
22 | expect(Pedro.maxibonsToGrab).to.equal(3);
23 | expect(Fran.maxibonsToGrab).to.equal(1);
24 | expect(Davide.maxibonsToGrab).to.equal(0);
25 | expect(Sergio.maxibonsToGrab).to.equal(2);
26 | expect(Jorge.maxibonsToGrab).to.equal(1);
27 | });
28 | });
29 |
--------------------------------------------------------------------------------
/test/maxibon/karumiHQs.spec.js:
--------------------------------------------------------------------------------
1 | import {
2 | Developer,
3 | KarumiHQs,
4 | Pedro,
5 | Davide,
6 | Sergio,
7 | Fran
8 | } from "../../src/maxibon/maxibon";
9 |
10 | describe("KarumiHQs", () => {
11 | it("starts the day with 10 maxibons", () => {
12 | const office = new KarumiHQs();
13 |
14 | expect(office.maxibonsLeft).to.equal(10);
15 | });
16 |
17 | jsc.property(
18 | "always has more than two maxibons in the fridge",
19 | arbitraryDeveloper(),
20 | dev => {
21 | const office = new KarumiHQs();
22 | office.openFridge(dev);
23 | return office.maxibonsLeft > 2;
24 | }
25 | );
26 |
27 | jsc.property(
28 | "request 10 more maxibons using the chat if there are less than 3 in the fridge",
29 | arbitraryHungryDeveloper(),
30 | dev => {
31 | const chat = new MockChat();
32 | const office = new KarumiHQs(chat);
33 |
34 | office.openFridge(dev);
35 |
36 | return (
37 | chat.messageSent === `Hi guys, I'm ${dev.name}. We need more maxibons!`
38 | );
39 | }
40 | );
41 |
42 | jsc.property(
43 | "never request more maxibons to the team using the chat if there are more than 2 in the fridge",
44 | arbitraryNotSoHungryDeveloper(),
45 | dev => {
46 | const chat = new MockChat();
47 | const office = new KarumiHQs(chat);
48 |
49 | office.openFridge(dev);
50 |
51 | return typeof chat.messageSent === "undefined";
52 | }
53 | );
54 |
55 | jsc.property(
56 | "always has more than two maxibons in the fridge even if some karumies grab maxibons in group",
57 | arbitraryDevelopers(),
58 | devs => {
59 | const office = new KarumiHQs();
60 | office.openFridge(devs);
61 | return office.maxibonsLeft > 2;
62 | }
63 | );
64 |
65 | const testScenarios = [
66 | [[Pedro], 7],
67 | [[Pedro, Davide], 7],
68 | [[Pedro, Davide, Fran, Sergio], 4],
69 | [[Pedro, Davide, Fran, Sergio, Pedro, Davide, Fran, Sergio], 8]
70 | ];
71 |
72 | testScenarios.forEach(testScenario => {
73 | let devs = testScenario[0];
74 | let expectedMaxibonsLeft = testScenario[1];
75 | it(`if ${devs} grab some maxibons, the number of maxibons left is ${expectedMaxibonsLeft}`, () => {
76 | const office = new KarumiHQs();
77 |
78 | office.openFridge(devs);
79 |
80 | expect(office.maxibonsLeft).to.equal(expectedMaxibonsLeft);
81 | });
82 | });
83 |
84 | function arbitraryDeveloper() {
85 | return jsc.integer.smap(maxibonsToGrab => {
86 | const name = jsc.sampler(jsc.string)();
87 | return new Developer(name, maxibonsToGrab);
88 | });
89 | }
90 |
91 | function arbitraryDevelopers() {
92 | return jsc.nearray(arbitraryDeveloper());
93 | }
94 |
95 | function arbitraryHungryDeveloper() {
96 | return jsc.integer(8, Number.MAX_SAFE_INTEGER).smap(maxibonsToGrab => {
97 | const name = jsc.sampler(jsc.string)();
98 | return new Developer(name, maxibonsToGrab);
99 | });
100 | }
101 |
102 | function arbitraryNotSoHungryDeveloper() {
103 | return jsc.integer(0, 7).smap(maxibonsToGrab => {
104 | const name = jsc.sampler(jsc.string)();
105 | return new Developer(name, maxibonsToGrab);
106 | });
107 | }
108 |
109 | class MockChat {
110 | sendMessage(message) {
111 | this.messageSent = message;
112 | }
113 | }
114 | });
115 |
--------------------------------------------------------------------------------
/test/potter/potter.spec.js:
--------------------------------------------------------------------------------
1 | import { calculatePrice, HarryPotterBook } from "../../src/potter/potter";
2 |
3 | describe("Potter spec", () => {
4 | it("an empty cart is free", () => {
5 | expect(calculatePrice([])).to.equal(0);
6 | });
7 |
8 | jsc.property("just one book costs 8.0 euros", arbitraryBook(), book => {
9 | return calculatePrice([book]) === 8.0;
10 | });
11 |
12 | jsc.property(
13 | "if there are two different books the cost of every repeated book is a 5% less",
14 | arbitraryDifferentBooks(2),
15 | cart => {
16 | return calculatePrice(cart) === 15.2;
17 | }
18 | );
19 |
20 | jsc.property(
21 | "if there are three different books the cost of every repeated book is a 10% less",
22 | arbitraryDifferentBooks(3),
23 | cart => {
24 | return calculatePrice(cart) === 21.6;
25 | }
26 | );
27 |
28 | jsc.property(
29 | "if there are four different books the cost of every repeated book is a 20% less",
30 | arbitraryDifferentBooks(4),
31 | cart => {
32 | return calculatePrice(cart) === 25.6;
33 | }
34 | );
35 |
36 | jsc.property(
37 | "if there are five different books the cost of every repeated book is a 25% less",
38 | arbitraryDifferentBooks(5),
39 | cart => {
40 | return calculatePrice(cart) === 30.0;
41 | }
42 | );
43 |
44 | jsc.property(
45 | "if all the books are the same there is no discount",
46 | arbitrarySameBooks(),
47 | cart => {
48 | return calculatePrice(cart) === cart.length * 8.0;
49 | }
50 | );
51 |
52 | it("2 book1, 2 book2, 2 book2, 2 book3, 1 book4 and 1 book5 costs 51.60 EUR", () => {
53 | const cart = [
54 | HarryPotterBook.BOOK_1,
55 | HarryPotterBook.BOOK_1,
56 | HarryPotterBook.BOOK_2,
57 | HarryPotterBook.BOOK_2,
58 | HarryPotterBook.BOOK_3,
59 | HarryPotterBook.BOOK_3,
60 | HarryPotterBook.BOOK_4,
61 | HarryPotterBook.BOOK_5
62 | ];
63 |
64 | expect(calculatePrice(cart)).to.equal(51.6);
65 | });
66 |
67 | it("2 book1, 1 book2 costs 23,2 EUR", () => {
68 | const cart = [
69 | HarryPotterBook.BOOK_1,
70 | HarryPotterBook.BOOK_1,
71 | HarryPotterBook.BOOK_2
72 | ];
73 |
74 | expect(calculatePrice(cart)).to.equal(23.2);
75 | });
76 |
77 | function arbitraryBook() {
78 | return jsc.suchthat(
79 | jsc.oneof(
80 | jsc.constant(HarryPotterBook.BOOK_1),
81 | jsc.constant(HarryPotterBook.BOOK_2),
82 | jsc.constant(HarryPotterBook.BOOK_3),
83 | jsc.constant(HarryPotterBook.BOOK_4),
84 | jsc.constant(HarryPotterBook.BOOK_5)
85 | ),
86 | gesture => typeof gesture !== "undefined"
87 | );
88 | }
89 |
90 | function arbitrarySameBooks() {
91 | const book = jsc.sampler(arbitraryBook())();
92 | return jsc.array(jsc.constant(book));
93 | }
94 |
95 | function arbitraryDifferentBooks(numberOfDifferentBooks) {
96 | return jsc.suchthat(
97 | jsc.nearray(jsc.elements(HarryPotterBook.enumValues)),
98 | array =>
99 | array.length === numberOfDifferentBooks &&
100 | array.every(x => array.filter(y => y === x).length === 1)
101 | );
102 | }
103 | });
104 |
--------------------------------------------------------------------------------
/test/prime-factors/prime-factors.spec.js:
--------------------------------------------------------------------------------
1 | import primeFactors from "../../src/prime-factors/prime-factors";
2 |
3 | describe("Prime factors spec", () => {
4 | jsc.property(
5 | "positive numbers have at least one prime factor",
6 | arbitraryPositiveInteger(),
7 | x => {
8 | const factors = primeFactors(x);
9 | return factors.length >= 1;
10 | }
11 | );
12 |
13 | jsc.property(
14 | "prime numbers have just one prime factor equal to the prime number",
15 | arbitraryPrimeNumber(),
16 | x => {
17 | return primeFactors(x).length === 1;
18 | }
19 | );
20 |
21 | jsc.property(
22 | "the product of a number prime factors is equal to the number",
23 | arbitraryPositiveInteger(),
24 | x => {
25 | return primeFactors(x).reduce((acc, x) => acc * x) === x;
26 | }
27 | );
28 |
29 | jsc.property(
30 | "if the number is not prime the number of prime factors is at least two",
31 | arbitraryNotPrimeNumber(),
32 | x => {
33 | return primeFactors(x).length >= 2;
34 | }
35 | );
36 |
37 | function arbitraryPositiveInteger() {
38 | return jsc.integer.smap(x => Math.abs(x) + 2);
39 | }
40 |
41 | function arbitraryPrimeNumber() {
42 | return jsc.suchthat(arbitraryPositiveInteger(), x => isPrime(x));
43 | }
44 |
45 | function arbitraryNotPrimeNumber() {
46 | return jsc.suchthat(arbitraryPositiveInteger(), x => !isPrime(x));
47 | }
48 |
49 | function isPrime(x) {
50 | const numbers = [...Array(x).keys()].map((v, i) => i);
51 | return numbers.filter(y => x % y === 0).length === 1;
52 | }
53 | });
54 |
--------------------------------------------------------------------------------
/test/rock-paper-scissors/rock-paper-scissors.spec.js:
--------------------------------------------------------------------------------
1 | import {
2 | Gesture,
3 | Player,
4 | Result,
5 | whoWins
6 | } from "../../src/rock-paper-scissors/rock-paper-scissors";
7 |
8 | describe("Rock paper scissors spec", () => {
9 | const tests = [
10 | {
11 | p1: new Player("p1", Gesture.ROCK),
12 | p2: new Player("p2", Gesture.SCISSORS),
13 | expectedResult: Result.PLAYER_1_WINS
14 | },
15 | {
16 | p1: new Player("p1", Gesture.PAPER),
17 | p2: new Player("p2", Gesture.ROCK),
18 | expectedResult: Result.PLAYER_1_WINS
19 | },
20 | {
21 | p1: new Player("p1", Gesture.SCISSORS),
22 | p2: new Player("p2", Gesture.PAPER),
23 | expectedResult: Result.PLAYER_1_WINS
24 | },
25 | {
26 | p1: new Player("p1", Gesture.SCISSORS),
27 | p2: new Player("p2", Gesture.ROCK),
28 | expectedResult: Result.PLAYER_2_WINS
29 | },
30 | {
31 | p1: new Player("p1", Gesture.ROCK),
32 | p2: new Player("p2", Gesture.PAPER),
33 | expectedResult: Result.PLAYER_2_WINS
34 | },
35 | {
36 | p1: new Player("p1", Gesture.PAPER),
37 | p2: new Player("p2", Gesture.SCISSORS),
38 | expectedResult: Result.PLAYER_2_WINS
39 | }
40 | ];
41 |
42 | tests.forEach(testScenario => {
43 | const p1 = testScenario.p1;
44 | const p2 = testScenario.p2;
45 | const expectedResult = testScenario.expectedResult;
46 | it(`${p1.gesture.name} vs ${p2.gesture
47 | .name} should finish the game as ${expectedResult.name}`, () => {
48 | expect(whoWins(p1, p2)).to.equal(expectedResult);
49 | });
50 | });
51 |
52 | jsc.property(
53 | "returns draw if the gesture is the same",
54 | arbitraryGesture(),
55 | gesture => {
56 | const p1 = new Player("p1", gesture);
57 | const p2 = new Player("p2", gesture);
58 | return whoWins(p1, p2) === Result.DRAW;
59 | }
60 | );
61 |
62 | function arbitraryGesture() {
63 | return jsc.suchthat(
64 | jsc.oneof(
65 | jsc.constant(Gesture.ROCK),
66 | jsc.constant(Gesture.Paper),
67 | jsc.constant(Gesture.SCISSORS)
68 | ),
69 | gesture => typeof gesture !== "undefined"
70 | );
71 | }
72 | });
73 |
--------------------------------------------------------------------------------
/test/roman-numerals/roman-numerals.spec.js:
--------------------------------------------------------------------------------
1 | import { toRoman, toArabic } from "../../src/roman-numerals/roman-numerals";
2 |
3 | describe("Roman numerals spec", () => {
4 | jsc.property(
5 | "translate from arabic to numeral and back to roman should return the same value",
6 | arbitraryArabic(),
7 | arabic => {
8 | const romanNumeral = toRoman(arabic);
9 | return arabic === toArabic(romanNumeral);
10 | }
11 | );
12 |
13 | jsc.property(
14 | "arabic numbers greater than zero returns non empty string as roman numeral",
15 | arbitraryNonZeroArabic(),
16 | arabic => {
17 | return toRoman(arabic).length > 0;
18 | }
19 | );
20 |
21 | jsc.property(
22 | "roman numerals V, D or L can never be repeated",
23 | arbitraryArabic(),
24 | arabic => {
25 | const romanNumeral = toRoman(arabic);
26 | const containsAsMuchOneV = containsAsMuchOne(romanNumeral, "V");
27 | const containsAsMuchOneD = containsAsMuchOne(romanNumeral, "D");
28 | const containsAsMuchOneL = containsAsMuchOne(romanNumeral, "L");
29 | return containsAsMuchOneV && containsAsMuchOneD && containsAsMuchOneL;
30 | }
31 | );
32 |
33 | function containsAsMuchOne(string, value) {
34 | return Array.of(string).filter(s => s === value).length <= 1;
35 | }
36 |
37 | function arbitraryArabic() {
38 | return jsc.integer(0, 3000);
39 | }
40 |
41 | function arbitraryNonZeroArabic() {
42 | return jsc.suchthat(arbitraryArabic(), x => x !== 0);
43 | }
44 | });
45 |
--------------------------------------------------------------------------------
/test/string-calculator/stringCalculator.spec.js:
--------------------------------------------------------------------------------
1 | import stringCalculator from "../../src/string-calculator/string-calculator";
2 |
3 | describe("String calculator spec", () => {
4 | it("should return 0 for an empty string", () => {
5 | const result = stringCalculator("");
6 |
7 | expect(result).to.equal(0);
8 | });
9 |
10 | it("should return the number inside the string if it just contains one number", () => {
11 | const result = stringCalculator("1");
12 |
13 | expect(result).to.equal(1);
14 | });
15 |
16 | it("should return the sum of two consecutive numbers separated by ','", () => {
17 | const result = stringCalculator("1,1");
18 |
19 | expect(result).to.equal(2);
20 | });
21 |
22 | it("should return the sum of two consecutive numbers separated by '\n'", () => {
23 | const result = stringCalculator("2\n3");
24 |
25 | expect(result).to.equal(5);
26 | });
27 |
28 | it("should return a big list of numbers separated by ','", () => {
29 | const result = stringCalculator("1,1,1,1,1,1,1,1,1,1,1");
30 |
31 | expect(result).to.equal(11);
32 | });
33 |
34 | it("should return 0 if the delimiter is customized but there are no values", () => {
35 | const result = stringCalculator("//x");
36 |
37 | expect(result).to.equal(0);
38 | });
39 |
40 | it("should return 1 if the delimiter is customized and the number inside the string is 1", () => {
41 | const result = stringCalculator("//x1");
42 |
43 | expect(result).to.equal(1);
44 | });
45 |
46 | it("should return the sum of big numbers separated by a custom delimiter", () => {
47 | const result = stringCalculator(
48 | "//&1665212997&1662109966&139852790&-866795925"
49 | );
50 |
51 | expect(result).to.equal(2600379828);
52 | });
53 |
54 | jsc.property(
55 | "result is always greater than zero if the array is not empty and full of positive values",
56 | arbitraryNonEmptyStringFullOfPositiveNumbersSeparatedByComas(),
57 | input => {
58 | return stringCalculator(input) > 0;
59 | }
60 | );
61 |
62 | function arbitraryNonEmptyStringFullOfPositiveNumbersSeparatedByComas() {
63 | return jsc.nearray(arbitraryPositiveInt()).smap(array => array.join(","));
64 | }
65 |
66 | function arbitraryPositiveInt() {
67 | return jsc.int32.smap(x => Math.abs(x));
68 | }
69 | });
70 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 |
3 | module.exports = {
4 | entry: "./src/index.js",
5 | output: {
6 | path: path.resolve(__dirname, "dist"),
7 | filename: "bundle.js"
8 | },
9 | module: {
10 | loaders: [
11 | {
12 | test: /\.js$/,
13 | exclude: /(node_modules|bower_components)/,
14 | use: [
15 | {
16 | loader: "babel-loader",
17 | options: {
18 | presets: ["env"]
19 | }
20 | }
21 | ]
22 | }
23 | ]
24 | }
25 | };
26 |
--------------------------------------------------------------------------------