forked from kolplattformen/skolplattformen
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
acf4828
commit 084e961
Showing
14 changed files
with
591 additions
and
1,999 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,9 @@ | ||
module.exports = { | ||
collectCoverageFrom: ['**/*.{ts}', '!**/node_modules/**', '!**/tests/**', '!**/coverage/**', '!jest.config.js'], | ||
coverageThreshold: { | ||
global: { | ||
branches: 100, | ||
functions: 100, | ||
lines: 100, | ||
statements: 100, | ||
}, | ||
}, | ||
moduleNameMapper: { | ||
'\\.(css|less)$': '<rootDir>/__mocks__/styleMock.js', | ||
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': | ||
'<rootDir>/__mocks__/fileMock.js', | ||
}, | ||
setupFiles: ['<rootDir>/test.setup.js'], | ||
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'], | ||
testPathIgnorePatterns: ['/.next/', '/node_modules/', '/tests/', '/coverage/'], | ||
preset: 'ts-jest', | ||
testEnvironment: 'node', | ||
transform: { | ||
'^.+\\.ts$': 'babel-jest', | ||
'.(ts|tsx)': '<rootDir>/node_modules/ts-jest/preprocessor.js' | ||
}, | ||
testRegex: '(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$', | ||
moduleFileExtensions: ["ts", "tsx", "js"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
const mockAxios: any = jest.genMockFromModule('axios') | ||
|
||
// this is the key to fix the axios.create() undefined error! | ||
mockAxios.create = jest.fn(() => mockAxios) | ||
|
||
export default mockAxios |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { AxiosAdapter, AxiosInstance } from 'axios' | ||
import routes from './routes' | ||
import { Child } from './types' | ||
|
||
export const list = (client: AxiosInstance) => async (): Promise<Child[]> => { | ||
const url = routes.children | ||
const response = await client.get(url) | ||
return response.data | ||
} | ||
|
||
export const details = (client: AxiosAdapter) => async (id: string): Promise<Child> => ({}) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,59 @@ | ||
export default function foo(): void { | ||
alert('hello') | ||
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios' | ||
import { list } from './children' | ||
import { checkStatus, getCookies, login } from './login' | ||
import { EventEmitter } from 'events' | ||
|
||
const pause = async (ms: number) => new Promise<void>((r) => setTimeout(r, ms)) | ||
|
||
const emitter = new EventEmitter() | ||
const init = () => { | ||
const config: AxiosRequestConfig = { | ||
headers: { | ||
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.87 Safari/537.36' | ||
}, | ||
maxRedirects: 0, | ||
withCredentials: true | ||
} | ||
const client = axios.create(config) | ||
let cookies: any = {} | ||
|
||
client.interceptors.request.use((config) => { | ||
console.log('request', config.method, config.url) | ||
config.headers.Cookie = Object.entries(cookies) | ||
.map(([key, value]) => `${key}=${value}`) | ||
.join('; ') | ||
return config | ||
}) | ||
client.interceptors.response.use((response) => { | ||
console.log('response', response.status, response.statusText, response.headers['set-cookie']) | ||
if (response.headers['set-cookie']) { | ||
const setCookies: string[] = response.headers['set-cookie'] | ||
setCookies.map((c) => c.split('=')).forEach(([key, value]) => cookies[key] = value) | ||
} | ||
return response | ||
}) | ||
|
||
return { | ||
...emitter, | ||
login: async (personalNumber: string) => { | ||
const ticket = await login(client)(personalNumber) | ||
await pause(1000) | ||
const check = checkStatus(client)(ticket) | ||
check.on('OK', async () => { | ||
console.log('get cookie') | ||
const newCookies = await getCookies(client)() | ||
cookies = {...cookies, ...newCookies} | ||
console.log(cookies) | ||
|
||
emitter.emit('login') | ||
}) | ||
return check | ||
}, | ||
getChildren: async () => { | ||
const result = await list(client)() | ||
return result | ||
}, | ||
} | ||
} | ||
|
||
export default init |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,64 @@ | ||
import { Client } from './client' | ||
import { login } from './login' | ||
import routes from './routes' | ||
import axios, { AxiosInstance } from 'axios' | ||
import { login, checkStatus, getCookie } from './login' | ||
|
||
jest.mock('axios') | ||
|
||
let client: jest.Mocked<AxiosInstance> | ||
|
||
describe('login', () => { | ||
let client: jest.Mocked<Client> | ||
beforeEach(() => { | ||
client = { | ||
post: jest.fn(), | ||
} | ||
client = axios.create() as jest.Mocked<AxiosInstance> | ||
client.get.mockReset() | ||
client.post.mockReset() | ||
}) | ||
it('returns the correct result', async () => { | ||
const personalNumber = 'my personal number' | ||
const response = { | ||
json: async () => ({ | ||
describe('#login', () => { | ||
it('returns the correct result', async () => { | ||
const personalNumber = 'my personal number' | ||
const data = { | ||
token: '9462cf77-bde9-4029-bb41-e599f3094613', | ||
order: '5fe57e4c-9ad2-4b52-b794-48adef2f6663', | ||
} | ||
|
||
client.post.mockResolvedValue({ data }) | ||
const result = await login(client)(personalNumber) | ||
|
||
expect(result).toEqual({ order: '5fe57e4c-9ad2-4b52-b794-48adef2f6663' }) | ||
}) | ||
}) | ||
describe('#checkStatus', () => { | ||
const ticket = { order: '5fe57e4c-9ad2-4b52-b794-48adef2f6663' } | ||
|
||
it('emits PENDING', (done) => { | ||
client.get.mockResolvedValue({ data: 'PENDING' }) | ||
|
||
const check = checkStatus(client)(ticket) | ||
check.on('PENDING', async () => { | ||
await check.cancel() | ||
done() | ||
}) | ||
}) | ||
it('retries on PENDING', (done) => { | ||
client.get.mockResolvedValueOnce({ data: 'PENDING' }) | ||
client.get.mockResolvedValueOnce({ data: 'OK' }) | ||
|
||
const check = checkStatus(client)(ticket) | ||
check.on('OK', () => { | ||
expect(client.get).toHaveBeenCalledTimes(2) | ||
done() | ||
}) | ||
}) | ||
}) | ||
describe('#getCookie', () => { | ||
it('sets cookie as client interceptor', async () => { | ||
client.get.mockResolvedValue({ | ||
headers: { | ||
'set-cookie': 'cookie', | ||
}, | ||
}) | ||
} | ||
|
||
client.post.mockResolvedValue(response) | ||
const result = await login(client)(personalNumber) | ||
const cookie = await getCookie(client)() | ||
|
||
expect(result).toEqual({ token: '9462cf77-bde9-4029-bb41-e599f3094613' }) | ||
expect(cookie).toEqual('cookie') | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,87 @@ | ||
import { Client } from './client' | ||
import { EventEmitter } from 'events' | ||
import { AxiosError, AxiosInstance, AxiosResponse } from 'axios' | ||
import routes from './routes' | ||
import { Auth } from './types' | ||
import { AuthTicket } from './types' | ||
|
||
export const login = (client: Client) => async ( | ||
personalNumber: string, | ||
): Promise<Auth> => { | ||
export const login = (client: AxiosInstance) => async (personalNumber: string): Promise<AuthTicket> => { | ||
const url = routes.login(personalNumber) | ||
const result = await client.post(url) | ||
const { token } = await result.json() | ||
return { token } | ||
const result = await client.get<AuthTicket>(url) | ||
return { order: result.data.order } | ||
} | ||
|
||
/* | ||
export enum LoginEvent { | ||
OK = 'OK', | ||
PENDING = 'PENDING', | ||
ERROR = 'ERROR', | ||
USER_SIGN = 'USER_SIGN', | ||
} | ||
*/ | ||
|
||
export class LoginStatus extends EventEmitter { | ||
private url: string | ||
|
||
private client: AxiosInstance | ||
|
||
private cancelled: boolean = false | ||
|
||
constructor(client: AxiosInstance, url: string) { | ||
super() | ||
this.client = client | ||
this.url = url | ||
this.check() | ||
} | ||
|
||
async check() { | ||
const status = await this.client.get<string>(this.url) | ||
this.emit(status.data) | ||
if (!this.cancelled && status.data !== 'OK' && status.data !== 'ERROR!') { | ||
setTimeout(() => this.check(), 1000) | ||
} | ||
} | ||
|
||
async cancel() { | ||
this.cancelled = true | ||
} | ||
} | ||
|
||
export const checkStatus = (client: AxiosInstance) => (ticket: AuthTicket): LoginStatus => { | ||
const url = routes.loginStatus(ticket.order) | ||
return new LoginStatus(client, url) | ||
} | ||
|
||
const parseCookies = (newCookies: string[]): any => { | ||
return newCookies | ||
.map((c) => c.split('=')).map(([key, val]) => ({[key]: val})) | ||
.reduce((obj1, obj2) => ({...obj1, ...obj2})) | ||
} | ||
|
||
export const getCookies = (client: AxiosInstance) => async (url = routes.loginCookie, cookies = {}): Promise<any> => { | ||
try { | ||
const response = await client.get(url) | ||
if (response.headers['set-cookie']) { | ||
cookies = { | ||
...cookies, | ||
...parseCookies(response.headers['set-cookie']) | ||
} | ||
} | ||
return cookies | ||
} catch (err) { | ||
const { response } = err as AxiosError | ||
if (response?.status === 302) { | ||
if (response.headers['set-cookie']) { | ||
cookies = { | ||
...cookies, | ||
...parseCookies(response.headers['set-cookie']) | ||
} | ||
} | ||
if (response.headers.location) { | ||
return getCookies(client)(response.headers.location, cookies) | ||
} else { | ||
return cookies | ||
} | ||
} else { | ||
throw err | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,13 @@ | ||
const hosts = { | ||
login: 'https://login003.stockholm.se', | ||
etjanst: 'https://etjanst.stockholm.se', | ||
} | ||
|
||
const routes = { | ||
login: (personalNumber: string) => `https://login003.stockholm.se/NECSadcmbid/authenticate/NECSadcmbid?TARGET=-SM-HTTPS%3a%2f%2flogin001%2estockholm%2ese%2fNECSadc%2fmbid%2fb64startpage%2ejsp%3fstartpage%3daHR0cHM6Ly9ldGphbnN0LnN0b2NraG9sbS5zZS92YXJkbmFkc2hhdmFyZS9pbmxvZ2dhZDIvaGVt&initialize=bankid&personalNumber=${personalNumber}&_=${Date.now()}`, | ||
login: (personalNumber: string) => `${hosts.login}/NECSadcmbid/authenticate/NECSadcmbid?TARGET=-SM-HTTPS%3a%2f%2flogin001%2estockholm%2ese%2fNECSadc%2fmbid%2fb64startpage%2ejsp%3fstartpage%3daHR0cHM6Ly9ldGphbnN0LnN0b2NraG9sbS5zZS92YXJkbmFkc2hhdmFyZS9pbmxvZ2dhZDIvaGVt&initialize=bankid&personalNumber=${personalNumber}&_=${Date.now()}`, | ||
loginStatus: (order: string) => `${hosts.login}/NECSadcmbid/authenticate/NECSadcmbid?TARGET=-SM-HTTPS%3a%2f%2flogin001%2estockholm%2ese%2fNECSadc%2fmbid%2fb64startpage%2ejsp%3fstartpage%3daHR0cHM6Ly9ldGphbnN0LnN0b2NraG9sbS5zZS92YXJkbmFkc2hhdmFyZS9pbmxvZ2dhZDIvaGVt&verifyorder=${order}&_=${Date.now()}`, | ||
loginCookie: `${hosts.login}/NECSadcmbid/authenticate/SiteMinderAuthADC?TYPE=33554433&REALMOID=06-42f40edd-0c5b-4dbc-b714-1be1e907f2de&GUID=&SMAUTHREASON=0&METHOD=GET&SMAGENTNAME=IfNE0iMOtzq2TcxFADHylR6rkmFtwzoxRKh5nRMO9NBqIxHrc38jFyt56FASdxk1&TARGET=-SM-HTTPS%3a%2f%2flogin001%2estockholm%2ese%2fNECSadc%2fmbid%2fb64startpage%2ejsp%3fstartpage%3daHR0cHM6Ly9ldGphbnN0LnN0b2NraG9sbS5zZS92YXJkbmFkc2hhdmFyZS9pbmxvZ2dhZDIvR2V0Q2hpbGRyZW4%3d`, | ||
children: `${hosts.etjanst}/vardnadshavare/inloggad2/GetChildren`, | ||
} | ||
|
||
export default routes |
Oops, something went wrong.