diff --git a/src/.eslintrc.json b/.eslintrc.json
similarity index 100%
rename from src/.eslintrc.json
rename to .eslintrc.json
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3fdaf56..67c8355 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -25,14 +25,9 @@ jobs:
with:
node-version: 16
- name: Install dependencies
- run: |
- ls -la
- cd src
- npm ci
+ run: npm ci
- name: Run Vitest tests
- run: |
- cd src
- npx vitest test
+ run: npx vitest test
playwrite:
timeout-minutes: 60
runs-on: ubuntu-latest
@@ -42,17 +37,12 @@ jobs:
with:
node-version: 16
- name: Install dependencies
- run: |
- cd src
- npm ci
+ run: npm ci
- name: Install Playwright Browsers
- run: |
- cd src
- npx playwright install --with-deps
+ run: npx playwright install --with-deps
- name: Run Playwright tests
run: |
npm install -D @playwright/test
- cd src
npx playwright test
- uses: actions/upload-artifact@v3
if: always()
diff --git a/.github/workflows/github.yml b/.github/workflows/github.yml
index f58f450..d462d3e 100644
--- a/.github/workflows/github.yml
+++ b/.github/workflows/github.yml
@@ -16,7 +16,11 @@ jobs:
- uses: actions/setup-node@v3
with:
node-version: 16
+ - name: Install dependencies
+ run: npm ci
+ - name: Build
+ run: npm run build
- name: Deploy To GitHub Pages
uses: JamesIves/github-pages-deploy-action@v4
with:
- folder: src
\ No newline at end of file
+ folder: dist
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index b9cb86b..4e525c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,25 +1,27 @@
-# General
-.DS_Store
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
-# Node
node_modules
+dist
+dist-ssr
+*.local
-# Thumbnails
-._*
-
-# Yarn
-yarn-error.log
-
-# PHPStorm
-.idea/
-.idea_modules/
-
-# VSCode
+# Editor directories and files
.vscode/*
-!.vscode/settings.json
-!.vscode/tasks.json
-!.vscode/launch.json
!.vscode/extensions.json
-!.vscode/*.code-snippets
-.history/
-*.vsix
\ No newline at end of file
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+/test-results/
+/playwright-report/
+/playwright/.cache/
diff --git a/src/.nvmrc b/.nvmrc
similarity index 100%
rename from src/.nvmrc
rename to .nvmrc
diff --git a/README.md b/README.md
index 49d9a71..28eb3a9 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# TicTacToe Game
-This is a simple `HTML`, `CSS`, `JavaScript` based TicTacToe game.
+This is a simple `HTML`, `CSS`, `ECMA/Vite` based TicTacToe game.
The game is created as a code challenge.
## Demo
@@ -29,17 +29,15 @@ For more installation information, [Yarn Install Manual](https://classic.yarnpkg
#### NPM
```bash
-cd src
npm install
-npm run watch
+npm run dev
```
#### YARN
```bash
-cd src
yarn
-yarn run watch
+yarn dev
```
## Run Tests
@@ -47,21 +45,18 @@ yarn run watch
### Eslint
```bash
-cd src
-yarn run lint
+yarn lint
```
### End-To-End Tests
```bash
-cd src
-yarn run playwright
+yarn test:playwright
```
or
```bash
-cd src
npx playwright test
```
- [Playwright Additional Commands](documentation%2Fplaywright.md)
@@ -76,11 +71,11 @@ TODO: Rebuild in VITE and ECMA to facilitate the ability to unit test
ECMAScript.
```bash
-yarn run vitest
+yarn test:vitest
```
```bash
-yarn run vitest-coverage
+yarn test:vitest-coverage
```
- Visit https://vitest.dev/guide/ for more information.
@@ -97,6 +92,7 @@ welcome any feedback through GitHub.
- https://github.com/nvm-sh/nvm
- https://vitest.dev
- https://playwright.dev
+- https://vitejs.dev/
## License
diff --git a/coverage/base.css b/coverage/base.css
new file mode 100644
index 0000000..f418035
--- /dev/null
+++ b/coverage/base.css
@@ -0,0 +1,224 @@
+body, html {
+ margin:0; padding: 0;
+ height: 100%;
+}
+body {
+ font-family: Helvetica Neue, Helvetica, Arial;
+ font-size: 14px;
+ color:#333;
+}
+.small { font-size: 12px; }
+*, *:after, *:before {
+ -webkit-box-sizing:border-box;
+ -moz-box-sizing:border-box;
+ box-sizing:border-box;
+ }
+h1 { font-size: 20px; margin: 0;}
+h2 { font-size: 14px; }
+pre {
+ font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ margin: 0;
+ padding: 0;
+ -moz-tab-size: 2;
+ -o-tab-size: 2;
+ tab-size: 2;
+}
+a { color:#0074D9; text-decoration:none; }
+a:hover { text-decoration:underline; }
+.strong { font-weight: bold; }
+.space-top1 { padding: 10px 0 0 0; }
+.pad2y { padding: 20px 0; }
+.pad1y { padding: 10px 0; }
+.pad2x { padding: 0 20px; }
+.pad2 { padding: 20px; }
+.pad1 { padding: 10px; }
+.space-left2 { padding-left:55px; }
+.space-right2 { padding-right:20px; }
+.center { text-align:center; }
+.clearfix { display:block; }
+.clearfix:after {
+ content:'';
+ display:block;
+ height:0;
+ clear:both;
+ visibility:hidden;
+ }
+.fl { float: left; }
+@media only screen and (max-width:640px) {
+ .col3 { width:100%; max-width:100%; }
+ .hide-mobile { display:none!important; }
+}
+
+.quiet {
+ color: #7f7f7f;
+ color: rgba(0,0,0,0.5);
+}
+.quiet a { opacity: 0.7; }
+
+.fraction {
+ font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
+ font-size: 10px;
+ color: #555;
+ background: #E8E8E8;
+ padding: 4px 5px;
+ border-radius: 3px;
+ vertical-align: middle;
+}
+
+div.path a:link, div.path a:visited { color: #333; }
+table.coverage {
+ border-collapse: collapse;
+ margin: 10px 0 0 0;
+ padding: 0;
+}
+
+table.coverage td {
+ margin: 0;
+ padding: 0;
+ vertical-align: top;
+}
+table.coverage td.line-count {
+ text-align: right;
+ padding: 0 5px 0 20px;
+}
+table.coverage td.line-coverage {
+ text-align: right;
+ padding-right: 10px;
+ min-width:20px;
+}
+
+table.coverage td span.cline-any {
+ display: inline-block;
+ padding: 0 5px;
+ width: 100%;
+}
+.missing-if-branch {
+ display: inline-block;
+ margin-right: 5px;
+ border-radius: 3px;
+ position: relative;
+ padding: 0 4px;
+ background: #333;
+ color: yellow;
+}
+
+.skip-if-branch {
+ display: none;
+ margin-right: 10px;
+ position: relative;
+ padding: 0 4px;
+ background: #ccc;
+ color: white;
+}
+.missing-if-branch .typ, .skip-if-branch .typ {
+ color: inherit !important;
+}
+.coverage-summary {
+ border-collapse: collapse;
+ width: 100%;
+}
+.coverage-summary tr { border-bottom: 1px solid #bbb; }
+.keyline-all { border: 1px solid #ddd; }
+.coverage-summary td, .coverage-summary th { padding: 10px; }
+.coverage-summary tbody { border: 1px solid #bbb; }
+.coverage-summary td { border-right: 1px solid #bbb; }
+.coverage-summary td:last-child { border-right: none; }
+.coverage-summary th {
+ text-align: left;
+ font-weight: normal;
+ white-space: nowrap;
+}
+.coverage-summary th.file { border-right: none !important; }
+.coverage-summary th.pct { }
+.coverage-summary th.pic,
+.coverage-summary th.abs,
+.coverage-summary td.pct,
+.coverage-summary td.abs { text-align: right; }
+.coverage-summary td.file { white-space: nowrap; }
+.coverage-summary td.pic { min-width: 120px !important; }
+.coverage-summary tfoot td { }
+
+.coverage-summary .sorter {
+ height: 10px;
+ width: 7px;
+ display: inline-block;
+ margin-left: 0.5em;
+ background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
+}
+.coverage-summary .sorted .sorter {
+ background-position: 0 -20px;
+}
+.coverage-summary .sorted-desc .sorter {
+ background-position: 0 -10px;
+}
+.status-line { height: 10px; }
+/* yellow */
+.cbranch-no { background: yellow !important; color: #111; }
+/* dark red */
+.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
+.low .chart { border:1px solid #C21F39 }
+.highlighted,
+.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{
+ background: #C21F39 !important;
+}
+/* medium red */
+.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
+/* light red */
+.low, .cline-no { background:#FCE1E5 }
+/* light green */
+.high, .cline-yes { background:rgb(230,245,208) }
+/* medium green */
+.cstat-yes { background:rgb(161,215,106) }
+/* dark green */
+.status-line.high, .high .cover-fill { background:rgb(77,146,33) }
+.high .chart { border:1px solid rgb(77,146,33) }
+/* dark yellow (gold) */
+.status-line.medium, .medium .cover-fill { background: #f9cd0b; }
+.medium .chart { border:1px solid #f9cd0b; }
+/* light yellow */
+.medium { background: #fff4c2; }
+
+.cstat-skip { background: #ddd; color: #111; }
+.fstat-skip { background: #ddd; color: #111 !important; }
+.cbranch-skip { background: #ddd !important; color: #111; }
+
+span.cline-neutral { background: #eaeaea; }
+
+.coverage-summary td.empty {
+ opacity: .5;
+ padding-top: 4px;
+ padding-bottom: 4px;
+ line-height: 1;
+ color: #888;
+}
+
+.cover-fill, .cover-empty {
+ display:inline-block;
+ height: 12px;
+}
+.chart {
+ line-height: 0;
+}
+.cover-empty {
+ background: white;
+}
+.cover-full {
+ border-right: none !important;
+}
+pre.prettyprint {
+ border: none !important;
+ padding: 0 !important;
+ margin: 0 !important;
+}
+.com { color: #999 !important; }
+.ignore-none { color: #999; font-weight: normal; }
+
+.wrapper {
+ min-height: 100%;
+ height: auto !important;
+ height: 100%;
+ margin: 0 auto -48px;
+}
+.footer, .push {
+ height: 48px;
+}
diff --git a/coverage/block-navigation.js b/coverage/block-navigation.js
new file mode 100644
index 0000000..cc12130
--- /dev/null
+++ b/coverage/block-navigation.js
@@ -0,0 +1,87 @@
+/* eslint-disable */
+var jumpToCode = (function init() {
+ // Classes of code we would like to highlight in the file view
+ var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no'];
+
+ // Elements to highlight in the file listing view
+ var fileListingElements = ['td.pct.low'];
+
+ // We don't want to select elements that are direct descendants of another match
+ var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > `
+
+ // Selecter that finds elements on the page to which we can jump
+ var selector =
+ fileListingElements.join(', ') +
+ ', ' +
+ notSelector +
+ missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b`
+
+ // The NodeList of matching elements
+ var missingCoverageElements = document.querySelectorAll(selector);
+
+ var currentIndex;
+
+ function toggleClass(index) {
+ missingCoverageElements
+ .item(currentIndex)
+ .classList.remove('highlighted');
+ missingCoverageElements.item(index).classList.add('highlighted');
+ }
+
+ function makeCurrent(index) {
+ toggleClass(index);
+ currentIndex = index;
+ missingCoverageElements.item(index).scrollIntoView({
+ behavior: 'smooth',
+ block: 'center',
+ inline: 'center'
+ });
+ }
+
+ function goToPrevious() {
+ var nextIndex = 0;
+ if (typeof currentIndex !== 'number' || currentIndex === 0) {
+ nextIndex = missingCoverageElements.length - 1;
+ } else if (missingCoverageElements.length > 1) {
+ nextIndex = currentIndex - 1;
+ }
+
+ makeCurrent(nextIndex);
+ }
+
+ function goToNext() {
+ var nextIndex = 0;
+
+ if (
+ typeof currentIndex === 'number' &&
+ currentIndex < missingCoverageElements.length - 1
+ ) {
+ nextIndex = currentIndex + 1;
+ }
+
+ makeCurrent(nextIndex);
+ }
+
+ return function jump(event) {
+ if (
+ document.getElementById('fileSearch') === document.activeElement &&
+ document.activeElement != null
+ ) {
+ // if we're currently focused on the search input, we don't want to navigate
+ return;
+ }
+
+ switch (event.which) {
+ case 78: // n
+ case 74: // j
+ goToNext();
+ break;
+ case 66: // b
+ case 75: // k
+ case 80: // p
+ goToPrevious();
+ break;
+ }
+ };
+})();
+window.addEventListener('keydown', jumpToCode);
diff --git a/coverage/clover.xml b/coverage/clover.xml
new file mode 100644
index 0000000..537619f
--- /dev/null
+++ b/coverage/clover.xml
@@ -0,0 +1,6 @@
+
+
+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +
+ +| File | ++ | Statements | ++ | Branches | ++ | Functions | ++ | Lines | ++ |
|---|