From 8149dcc57ce1323cb408550a2e400ffaea5725b3 Mon Sep 17 00:00:00 2001 From: Petteri Tolonen Date: Thu, 18 Apr 2024 16:04:26 +0300 Subject: [PATCH 1/4] =?UTF-8?q?Vaihdettu=20p=C3=A4=C3=A4te=20not-found.js?= =?UTF-8?q?=20->=20not-found.tsx?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/{not-found.js => not-found.tsx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/app/{not-found.js => not-found.tsx} (100%) diff --git a/src/app/not-found.js b/src/app/not-found.tsx similarity index 100% rename from src/app/not-found.js rename to src/app/not-found.tsx From ba2557e5ab65867341254165eeac27341c218dd3 Mon Sep 17 00:00:00 2001 From: Petteri Tolonen Date: Thu, 18 Apr 2024 16:04:26 +0300 Subject: [PATCH 2/4] =?UTF-8?q?Toteutettu=20http-client=20pelk=C3=A4ll?= =?UTF-8?q?=C3=A4=20fetch:ll=C3=A4=20ja=20poistettu=20Xior?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 30 +------ package.json | 5 +- src/app/lib/http-client.ts | 144 ++++++++++++++++++++-------------- tests/e2e/playwright.setup.js | 1 + 4 files changed, 91 insertions(+), 89 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5f148cd49..03f940b85 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,8 +19,7 @@ "cookie": "^0.6.0", "next": "^14.2.0", "react": "^18", - "react-dom": "^18", - "xior": "^0.3.11" + "react-dom": "^18" }, "devDependencies": { "@playwright/test": "^1.42.0", @@ -38,8 +37,8 @@ "http-proxy-middleware": "^3.0.0", "husky": "^9.0.11", "jsdom": "^24.0.0", - "postcss": "^8", "lint-staged": "^15.2.2", + "postcss": "^8", "prettier": "^3.2.5", "prettier-eslint-cli": "^8.0.1", "typescript": "^5", @@ -8033,14 +8032,6 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/tiny-lru": { - "version": "11.2.5", - "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-11.2.5.tgz", - "integrity": "sha512-JpqM0K33lG6iQGKiigcwuURAKZlq6rHXfrgeL4/I8/REoyJTGU+tEMszvT/oTRVHG2OiylhGDjqPp1jWMlr3bw==", - "engines": { - "node": ">=12" - } - }, "node_modules/tinybench": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.6.0.tgz", @@ -8133,14 +8124,6 @@ "typescript": ">=4.2.0" } }, - "node_modules/ts-deepmerge": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/ts-deepmerge/-/ts-deepmerge-7.0.0.tgz", - "integrity": "sha512-WZ/iAJrKDhdINv1WG6KZIGHrZDar6VfhftG1QJFpVbOYZMYJLJOvZOo1amictRXVdBXZIgBHKswMTXzElngprA==", - "engines": { - "node": ">=14.13.1" - } - }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -8814,15 +8797,6 @@ } } }, - "node_modules/xior": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/xior/-/xior-0.3.11.tgz", - "integrity": "sha512-33l7CNzTS07qUMfyr1zWXR1x6FFsrlCdjyXV+i2GliUO4lu3TCN/Pv767wccYMoPyy7eSnoWzvrX4tZ9HqC+yw==", - "dependencies": { - "tiny-lru": "^11.2.5", - "ts-deepmerge": "^7.0.0" - } - }, "node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", diff --git a/package.json b/package.json index f2d525fb6..a39426a90 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,7 @@ "cookie": "^0.6.0", "next": "^14.2.0", "react": "^18", - "react-dom": "^18", - "xior": "^0.3.11" + "react-dom": "^18" }, "devDependencies": { "@playwright/test": "^1.42.0", @@ -45,8 +44,8 @@ "http-proxy-middleware": "^3.0.0", "husky": "^9.0.11", "jsdom": "^24.0.0", - "postcss": "^8", "lint-staged": "^15.2.2", + "postcss": "^8", "prettier": "^3.2.5", "prettier-eslint-cli": "^8.0.1", "typescript": "^5", diff --git a/src/app/lib/http-client.ts b/src/app/lib/http-client.ts index a1c998b43..b225818b0 100644 --- a/src/app/lib/http-client.ts +++ b/src/app/lib/http-client.ts @@ -1,79 +1,107 @@ -import xior, { XiorError, XiorInterceptorRequestConfig } from 'xior'; import { getCookies } from './cookie'; import { redirect } from 'next/navigation'; import { configuration } from './configuration'; -const createClient = () => { - const client_ = xior.create({ - headers: { - Accept: 'application/json', - 'Caller-id': '1.2.246.562.10.00000000001.valintojen-toteuttaminen', - }, - }); - - client_.interceptors.request.use( - (request: XiorInterceptorRequestConfig) => { - const { method } = request; - if (['post', 'put', 'patch', 'delete'].includes(method)) { - const csrfCookie = getCookies()['CSRF']; - if (csrfCookie) { - request.headers.CSRF = csrfCookie; - } - } - return request; - }, - ); - return client_; +const doFetch = async (request: Request) => { + try { + const response = await fetch(request); + return response.status >= 400 + ? Promise.reject(response) + : Promise.resolve(response); + } catch (e) { + return Promise.reject(e); + } }; -export const client = createClient(); - -const bareClient = createClient(); - -const isUnauthorized = (error: XiorError) => { - return error.response?.status === 401; +const isUnauthenticated = (response: Response) => { + return response?.status === 401; }; const isRedirected = (response: Response) => { return response.redirected; }; +const redirectToLogin = () => { + const loginUrl = new URL(configuration.loginUrl); + loginUrl.searchParams.set('service', window.location.href); + redirect(loginUrl.toString()); +}; + +const makeBareRequest = (request: Request) => { + const { method } = request; + let modifiedOptions: RequestInit = { + headers: { + 'Caller-id': '1.2.246.562.10.00000000001.valintojen-toteuttaminen', + }, + }; + if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) { + const csrfCookie = getCookies()['CSRF']; + if (csrfCookie) { + modifiedOptions.headers = { + CSRF: csrfCookie, + }; + } + } + + return doFetch(new Request(request, modifiedOptions)); +}; + const retryWithLogin = async (request: any, loginUrl: string) => { - await bareClient.request(loginUrl); - return await bareClient.request(request); + await makeBareRequest(new Request(loginUrl)); + return await makeBareRequest(request); }; -client.interceptors.response.use( - (data) => { - if (isRedirected(data.response)) { - if (data.response.url.includes('/cas/login')) { - const loginUrl = new URL(configuration.loginUrl); - loginUrl.searchParams.set('service', window.location.href); - redirect(loginUrl.toString()); +const responseToData = async (res: Response) => { + const contentType = res.headers.get('Content-Type') ?? 'application/json'; + + if (contentType?.includes('json')) { + try { + const result = { data: await res.json() }; + return result; + } catch (e) { + console.error('Parsing fetch response body as JSON failed!'); + return Promise.reject(e); + } + } else { + return { data: await res.text() }; + } +}; + +const makeRequest = async (request: Request) => { + try { + const response = await makeBareRequest(request); + + if (isRedirected(response)) { + if (response.url.includes('/cas/login')) { + redirectToLogin(); } } - // NOTE: oppijanumerorekisteri ohjautuu tässä omaan login-service-osoitteeseensa, josta tulee 406, mutta sen jälkeen pyynnöt toimii - return data; - }, - async (error) => { - console.log(error); - if (isUnauthorized(error)) { - const request = error.request; - try { - if (request?.url?.includes('/kouta-internal')) { - return await retryWithLogin( - request, - configuration.koutaInternalLogin, - ); + + return responseToData(response); + } catch (error: unknown) { + if (error instanceof Response) { + if (isUnauthenticated(error)) { + try { + if (request?.url?.includes('/kouta-internal')) { + const resp = await retryWithLogin( + request, + configuration.koutaInternalLogin, + ); + + return responseToData(resp); + } + } catch (e) { + return Promise.reject(e); } - } catch (e) { - console.error(`Retry with login failed for request: ${request?.url}`); } } + return Promise.reject(error); + } +}; - // Ei autentikaatiota, ohjataan login-sivulle! - const loginUrl = new URL(configuration.loginUrl); - loginUrl.searchParams.set('service', window.location.href); - redirect(loginUrl.toString()); - }, -); +export const client = { + get: (url: string, options: RequestInit = {}) => + makeRequest(new Request(url, { method: 'GET', ...options })), + post: (url: string, options: RequestInit = {}) => + makeRequest(new Request(url, { method: 'POST', ...options })), +}; diff --git a/tests/e2e/playwright.setup.js b/tests/e2e/playwright.setup.js index ecafdbde7..cd75b9eda 100644 --- a/tests/e2e/playwright.setup.js +++ b/tests/e2e/playwright.setup.js @@ -12,6 +12,7 @@ export default async function playwrightSetup() { response.end(); return; } else if (request.url.includes(`henkilo/current/asiointiKieli`)) { + response.setHeader('Content-Type', 'text/plain'); response.write('fi'); response.end(); return; From 0f2f39e12952afc4af2a3462f977d682607edaa1 Mon Sep 17 00:00:00 2001 From: Petteri Tolonen Date: Fri, 19 Apr 2024 09:35:04 +0300 Subject: [PATCH 3/4] =?UTF-8?q?P=C3=A4ivitetty=20actionit=20CI:ss=C3=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yml | 88 ++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 45 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 98234c6fb..a75a8fee4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,62 +1,60 @@ name: Valintojen toteuttaminen workflow on: push: - branches: [ main, master ] + branches: [main, master] pull_request: - branches: [ main, master ] + branches: [main, master] jobs: lint: timeout-minutes: 10 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version-file: '.nvmrc' - - name: Install dependencies - run: npm ci - - name: Run lint - run: npm run lint + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Install dependencies + run: npm ci + - name: Run lint + run: npm run lint test: timeout-minutes: 10 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version-file: '.nvmrc' - - name: Install dependencies - run: npm ci - - name: Run unit tests - run: npm test + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Install dependencies + run: npm ci + - name: Run unit tests + run: npm test e2e: timeout-minutes: 60 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version-file: '.nvmrc' - - name: Install dependencies - run: npm ci - - name: Install Playwright Browsers - run: npx playwright install --with-deps - - name: install mkcert - run: | - curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64" - chmod +x mkcert-v*-linux-amd64 - sudo cp mkcert-v*-linux-amd64 /usr/local/bin/mkcert - - name: Create dev certificates - run: npm run create-dev-certs - - name: Start the app - run: npm run dev-test & - - name: Run Playwright tests - run: npx playwright test - - uses: actions/upload-artifact@v3 - if: always() - with: - name: playwright-report - path: playwright-report/ - retention-days: 10 - - + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + - name: Install dependencies + run: npm ci + - name: Install Playwright Browsers + run: npx playwright install --with-deps + - name: install mkcert + run: | + curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64" + chmod +x mkcert-v*-linux-amd64 + sudo cp mkcert-v*-linux-amd64 /usr/local/bin/mkcert + - name: Create dev certificates + run: npm run create-dev-certs + - name: Start the app + run: npm run dev-test & + - name: Run Playwright tests + run: npx playwright test + - uses: actions/upload-artifact@v4 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 10 From 2b6ebf0e2ef20ee9244593bdd270c5c720b76640 Mon Sep 17 00:00:00 2001 From: Petteri Tolonen Date: Fri, 19 Apr 2024 09:41:35 +0300 Subject: [PATCH 4/4] =?UTF-8?q?Muistinnetaan=20Playwright-selaimet=20CI:ss?= =?UTF-8?q?=C3=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a75a8fee4..eb725a9d6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,9 +38,20 @@ jobs: with: node-version-file: '.nvmrc' - name: Install dependencies - run: npm ci - - name: Install Playwright Browsers + run: npm ci --no-audit --prefer-offline + - name: Get installed Playwright version + id: playwright-version + run: echo "PLAYWRIGHT_VERSION=$(node -e "console.log(require('./package-lock.json').dependencies['@playwright/test'].version)")" >> $GITHUB_ENV + - name: Cache playwright binaries + uses: actions/cache@v4 + id: playwright-cache + with: + path: | + ~/.cache/ms-playwright + key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }} + - name: 'Install Playwright browsers' run: npx playwright install --with-deps + if: steps.playwright-cache.outputs.cache-hit != 'true' - name: install mkcert run: | curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64"