From c525e308ef01d736e7e307557d723ee83b2e7400 Mon Sep 17 00:00:00 2001 From: tonynazarov Date: Fri, 20 Sep 2024 08:15:40 +1200 Subject: [PATCH] Mapped entities --- README.md | 3 +- index.ts | 7 +- package.json | 15 +- src/Contracts.ts | 28 ++- src/ResponseDataDecorator.ts | 178 +++++++++---- src/domain/gtfs/entity/StopTime.ts | 86 +++++++ src/domain/gtfs/entity/Trip.ts | 1 + tests/unit/ClientBuilder.ts | 18 ++ .../Gtfs-rt/ServiceAlerts.test.ts | 235 ++++++++++++++++++ .../Gtfs-rt/TripUpdates.test.ts | 165 ++++++++++++ .../Gtfs-rt/VehiclePositions.test.ts | 153 ++++++++++++ .../Gtfs/Agencies.test.ts | 76 ++++++ .../Gtfs/Calendar.test.ts | 116 +++++++++ .../Gtfs/CalendarDates.test.ts | 68 +++++ .../Gtfs/FeedInfo.test.ts | 90 +++++++ .../ResponseDataDecorator/Gtfs/Routes.test.ts | 121 +++++++++ .../ResponseDataDecorator/Gtfs/Shapes.test.ts | 82 ++++++ .../Gtfs/StopTimes.test.ts | 110 ++++++++ .../ResponseDataDecorator/Gtfs/Stops.test.ts | 112 +++++++++ .../Gtfs/Transfers.test.ts | 87 +++++++ .../ResponseDataDecorator/Gtfs/Trips.test.ts | 118 +++++++++ .../StopPredictions.test.ts | 184 ++++++++++++++ .../TripCancellations.test.ts | 93 +++++++ 23 files changed, 2082 insertions(+), 64 deletions(-) create mode 100644 src/domain/gtfs/entity/StopTime.ts create mode 100644 tests/unit/ClientBuilder.ts create mode 100644 tests/unit/ResponseDataDecorator/Gtfs-rt/ServiceAlerts.test.ts create mode 100644 tests/unit/ResponseDataDecorator/Gtfs-rt/TripUpdates.test.ts create mode 100644 tests/unit/ResponseDataDecorator/Gtfs-rt/VehiclePositions.test.ts create mode 100644 tests/unit/ResponseDataDecorator/Gtfs/Agencies.test.ts create mode 100644 tests/unit/ResponseDataDecorator/Gtfs/Calendar.test.ts create mode 100644 tests/unit/ResponseDataDecorator/Gtfs/CalendarDates.test.ts create mode 100644 tests/unit/ResponseDataDecorator/Gtfs/FeedInfo.test.ts create mode 100644 tests/unit/ResponseDataDecorator/Gtfs/Routes.test.ts create mode 100644 tests/unit/ResponseDataDecorator/Gtfs/Shapes.test.ts create mode 100644 tests/unit/ResponseDataDecorator/Gtfs/StopTimes.test.ts create mode 100644 tests/unit/ResponseDataDecorator/Gtfs/Stops.test.ts create mode 100644 tests/unit/ResponseDataDecorator/Gtfs/Transfers.test.ts create mode 100644 tests/unit/ResponseDataDecorator/Gtfs/Trips.test.ts create mode 100644 tests/unit/ResponseDataDecorator/StopPredictions.test.ts create mode 100644 tests/unit/ResponseDataDecorator/TripCancellations.test.ts diff --git a/README.md b/README.md index f255c04..5e146f2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# Metlink API HTTP Client (Wellington) +# Metlink API HTTP Client (Wellington, New Zealand) +https://opendata.metlink.org.nz/ ## Install diff --git a/index.ts b/index.ts index 4f05cba..18e55e3 100644 --- a/index.ts +++ b/index.ts @@ -18,10 +18,11 @@ httpClient.getGtfsStopTimes("tripId"); httpClient.getGtfsStops(); httpClient.getGtfsTransfers(); httpClient.getGtfsTrips(); -httpClient.getGtfsServiceAlerts(); httpClient.getGtfsRtTripUpdates(); httpClient.getGtfsRtVehiclePositions(); httpClient.getStopPredictions("stopId"); +httpClient.getGtfsServiceAlerts(); + const query: Query = new Query(); query.dateCreated = Date.now().toString(); @@ -39,3 +40,7 @@ decorator.getGtfsCalendarDates() decorator.getGtfsFeedInfo() decorator.getGtfsRoutes("routeId") decorator.getGtfsShapes("shapeId") +decorator.getGtfsStopTimes("tripId"); +decorator.getGtfsStops(); +decorator.getGtfsTransfers(); +decorator.getGtfsTrips(); \ No newline at end of file diff --git a/package.json b/package.json index 06784ec..6a16f4c 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { - "name": "njs", + "name": "metlink-api-http-client", + "description": "HTTP Client for Metlink Wellington API", "version": "1.0.0", "main": "index.js", "scripts": { @@ -10,10 +11,14 @@ "index": "npx tsx index.nts" }, "type": "module", - "keywords": [], - "author": "", - "license": "ISC", - "description": "", + "keywords": [ + "Metlink", + "http client", + "Metlink Wellington", + "GTFS" + ], + "author": "Anton Nazarov", + "license": "MIT", "devDependencies": { "@jest/globals": "^29.7.0", "@types/ajv": "^0.0.5", diff --git a/src/Contracts.ts b/src/Contracts.ts index 03866b8..6714fcf 100644 --- a/src/Contracts.ts +++ b/src/Contracts.ts @@ -1,5 +1,3 @@ -import {Agency} from "./domain/gtfs/entity/Agency"; - export interface ResponseDTO { isCollection(): boolean; } @@ -15,8 +13,12 @@ export interface HeadersDictInterface { [key: string]: string; } -export abstract class Entity { +interface EntityInterface { + [key: string]: string | number | null | object; +} +export abstract class Entity implements EntityInterface { + [key: string]: string | number | null | object; } export interface HostInterface { @@ -27,32 +29,32 @@ export interface HostInterface { } export interface GTFSInterface { - getGtfsAgencies(): Promise; + getGtfsAgencies(): Promise; - getGtfsCalendar(): Promise; + getGtfsCalendar(): Promise; - getGtfsCalendarDates(): Promise; + getGtfsCalendarDates(): Promise; - getGtfsFeedInfo(): Promise; + getGtfsFeedInfo(): Promise; getGtfsRoutes( routeId: string | null, - ): Promise; + ): Promise; getGtfsShapes( shapeId: string, - ): Promise; + ): Promise; getGtfsStopTimes( tripId: string, - ): Promise; + ): Promise; getGtfsStops( routeId: string | null, tripId: string | null, - ): Promise; + ): Promise; - getGtfsTransfers(): Promise; + getGtfsTransfers(): Promise; getGtfsTrips( start: string | null, @@ -60,7 +62,7 @@ export interface GTFSInterface { routeId: string | null, tripId: string | null, end: string | null, - ): Promise; + ): Promise; } export interface GTFSRealTimeInterface { diff --git a/src/ResponseDataDecorator.ts b/src/ResponseDataDecorator.ts index f9e4314..c92861d 100644 --- a/src/ResponseDataDecorator.ts +++ b/src/ResponseDataDecorator.ts @@ -1,13 +1,17 @@ import MetlinkHttpClient from "./MetlinkHttpClient"; -import {MetlinkHttpClientInterface} from "./Contracts"; +import {MetlinkHttpClientInterface, TripCancellationQueryInterface} from "./Contracts"; import {Agency} from "./domain/gtfs/entity/Agency"; import {Calendar} from "./domain/gtfs/entity/Calendar"; import {CalendarDate} from "./domain/gtfs/entity/CalendarDate"; import {Feed} from "./domain/gtfs/entity/Feed"; import {Route} from "./domain/gtfs/entity/Route"; import {Shape} from "./domain/gtfs/entity/Shape"; +import {Stop} from "./domain/gtfs/entity/Stop"; +import {StopTime} from "./domain/gtfs/entity/StopTime"; +import {Transfer} from "./domain/gtfs/entity/Transfer"; +import {Trip} from "./domain/gtfs/entity/Trip"; -export class ResponseDataDecorator {//implements MetlinkHttpClientInterface { +export class ResponseDataDecorator implements MetlinkHttpClientInterface { private readonly httpClient: MetlinkHttpClient; constructor(client: MetlinkHttpClient) { @@ -15,7 +19,7 @@ export class ResponseDataDecorator {//implements MetlinkHttpClientInterface { } async getGtfsAgencies(): Promise { - const response = await this.httpClient.getGtfsAgencies(); + const response = await this.httpClient.getGtfsAgencies(); const entities: Agency[] = response.data.map((data: any) => { return new Agency( @@ -34,7 +38,7 @@ export class ResponseDataDecorator {//implements MetlinkHttpClientInterface { } async getGtfsCalendar(): Promise { - const response = await this.httpClient.getGtfsCalendar(); + const response = await this.httpClient.getGtfsCalendar(); const entities: Calendar[] = response.data.map((data: any) => { return new Calendar( @@ -54,9 +58,10 @@ export class ResponseDataDecorator {//implements MetlinkHttpClientInterface { return Promise.resolve(entities); } + // async getGtfsCalendarDates(): Promise { - const response = await this.httpClient.getGtfsCalendarDates(); + const response = await this.httpClient.getGtfsCalendarDates(); const entities: CalendarDate[] = response.data.map((data: any) => { return new CalendarDate( data.id, @@ -70,7 +75,7 @@ export class ResponseDataDecorator {//implements MetlinkHttpClientInterface { } async getGtfsFeedInfo(): Promise { - const response = await this.httpClient.getGtfsFeedInfo(); + const response = await this.httpClient.getGtfsFeedInfo(); const entities: Feed[] = response.data.map((data: any) => { return new Feed( @@ -87,8 +92,10 @@ export class ResponseDataDecorator {//implements MetlinkHttpClientInterface { return Promise.resolve(entities); } - async getGtfsRoutes(routeId: string | null): Promise { - const response = await this.httpClient.getGtfsRoutes(routeId); + async getGtfsRoutes( + routeId: string | null = null + ): Promise { + const response = await this.httpClient.getGtfsRoutes(routeId); const entities: Route[] = response.data.map((data: any) => { return new Route( @@ -110,7 +117,7 @@ export class ResponseDataDecorator {//implements MetlinkHttpClientInterface { } async getGtfsShapes(shapeId: string): Promise { - const response = await this.httpClient.getGtfsRoutes(shapeId); + const response = await this.httpClient.getGtfsShapes(shapeId); const entities: Shape[] = response.data.map((data: any) => { return new Shape( @@ -125,41 +132,124 @@ export class ResponseDataDecorator {//implements MetlinkHttpClientInterface { return Promise.resolve(entities); } - // - // async getGtfsStopTimes(tripId: string): Promise { - // return Promise.resolve(undefined); - // } - // - // async getGtfsStops(routeId: string | null, tripId: string | null): Promise { - // return Promise.resolve(undefined); - // } - // - // async getGtfsTransfers(): Promise { - // return Promise.resolve(undefined); - // } - // - // async getGtfsTrips(start: string | null, extraFields: string | null, routeId: string | null, tripId: string | null, end: string | null): Promise { - // return Promise.resolve(undefined); - // } - // - // async getGtfsRtTripUpdates(useProtoBuf: boolean): Promise { - // return Promise.resolve(undefined); - // } - // - // async getGtfsRtVehiclePositions(useProtoBuf: boolean): Promise { - // return Promise.resolve(undefined); - // } - // - // async getGtfsServiceAlerts(useProtoBuf: boolean): Promise { - // return Promise.resolve(undefined); - // } + + async getGtfsStopTimes(tripId: string): Promise { + const response = await this.httpClient.getGtfsStopTimes(tripId); + + const entities: StopTime[] = response.data.map((data: any) => { + return new StopTime( + data.id, + data.trip_id, + data.arrival_time, + data.departure_time, + data.stop_id, + data.stop_sequence, + data.shape_dist_traveled, + data.stop_headsign, + data.pickup_type, + data.drop_off_type, + data.timepoint, + ); + }); + + return Promise.resolve(entities); + } + + async getGtfsStops(routeId: string | null = null, tripId: string | null = null): Promise { + const response = await this.httpClient.getGtfsStops(routeId, tripId); + + const entities: Stop[] = response.data.map((data: any) => { + return new Stop( + data.id, + data.stop_id, + data.stop_code, + data.stop_name, + data.stop_desc, + data.zone_id, + data.stop_lat, + data.stop_lon, + data.location_type, + data.parent_station, + data.stop_url, + data.stop_timezone, + ); + }); + + return Promise.resolve(entities); + } + + async getGtfsTransfers(): Promise { + const response = await this.httpClient.getGtfsTransfers(); + + const entities: Transfer[] = response.data.map((data: any) => { + return new Transfer( + data.id, + data.from_stop_id, + data.to_stop_id, + data.transfer_type, + data.min_transfer_time, + data.from_trip_id, + data.to_trip_id, + ); + }); + + return Promise.resolve(entities); + } + + async getGtfsTrips( + start: string | null = null, + extraFields: string | null = null, + routeId: string | null = null, + tripId: string | null = null, + end: string | null = null + ): Promise { + const response = await this.httpClient.getGtfsTrips( + start, + extraFields, + routeId, + tripId, + end + ); + + const entities: Trip[] = response.data.map((data: any) => { + return new Trip( + data.id, + data.route_id, + data.service_id, + data.trip_id, + data.trip_headsign, + data.direction_id, + data.block_id, + data.shape_id, + data.wheelchair_accessible, + data.bikes_allowed, + data.origin_stop_id, + data.destination_stop_id, + ); + }); + + return Promise.resolve(entities); + } // - // async getStopPredictions(stopId: string | null): Promise { - // return Promise.resolve(undefined); - // } - // - // async getTripCancellation(query: TripCancellationQueryInterface | null): Promise { - // return Promise.resolve(undefined); - // } + async getGtfsRtTripUpdates(useProtoBuf: boolean): Promise { + return Promise.resolve(undefined); + } + + async getGtfsRtVehiclePositions(useProtoBuf: boolean): Promise { + return Promise.resolve(undefined); + } + + async getGtfsServiceAlerts(useProtoBuf: boolean): Promise { + return Promise.resolve(undefined); + } + + + async getStopPredictions(stopId: string | null): Promise { + return Promise.resolve(undefined); + } + + async getTripCancellation(query: TripCancellationQueryInterface | null): Promise { + return Promise.resolve(undefined); + } } \ No newline at end of file diff --git a/src/domain/gtfs/entity/StopTime.ts b/src/domain/gtfs/entity/StopTime.ts new file mode 100644 index 0000000..8079800 --- /dev/null +++ b/src/domain/gtfs/entity/StopTime.ts @@ -0,0 +1,86 @@ +import {Entity} from "../../../Contracts"; + +export class StopTime extends Entity { + private readonly _id: number; + private readonly _tripId: string; + private readonly _arrivalTime: string; + private readonly _departureTime: string; + private readonly _stopId: string; + private readonly _stopSequence: number; + private readonly _shapeDistTraveled: number; + private readonly _stopHeadSign: string; + private readonly _pickupType: number; + private readonly _dropOffType: number; + private readonly _timepoint: string; + + constructor( + id: number, + tripId: string, + arrivalTime: string, + departureTime: string, + stopId: string, + stopSequence: number, + shapeDistTraveled: number, + stopHeadSign: string, + pickupType: number, + dropOffType: number, + timepoint: string + ) { + super(); + this._id = id; + this._tripId = tripId; + this._arrivalTime = arrivalTime; + this._departureTime = departureTime; + this._stopId = stopId; + this._stopSequence = stopSequence; + this._shapeDistTraveled = shapeDistTraveled; + this._stopHeadSign = stopHeadSign; + this._pickupType = pickupType; + this._dropOffType = dropOffType; + this._timepoint = timepoint; + } + + get id(): number { + return this._id; + } + + get tripId(): string { + return this._tripId; + } + + get arrivalTime(): string { + return this._arrivalTime; + } + + get departureTime(): string { + return this._departureTime; + } + + get stopId(): string { + return this._stopId; + } + + get stopSequence(): number { + return this._stopSequence; + } + + get shapeDistTraveled(): number { + return this._shapeDistTraveled; + } + + get stopHeadSign(): string { + return this._stopHeadSign; + } + + get pickupType(): number { + return this._pickupType; + } + + get dropOffType(): number { + return this._dropOffType; + } + + get timepoint(): string { + return this._timepoint; + } +} \ No newline at end of file diff --git a/src/domain/gtfs/entity/Trip.ts b/src/domain/gtfs/entity/Trip.ts index 63a2430..e853355 100644 --- a/src/domain/gtfs/entity/Trip.ts +++ b/src/domain/gtfs/entity/Trip.ts @@ -14,6 +14,7 @@ export class Trip extends Entity { private readonly _originStopId: null | number; private readonly _destinationStopId: null | number; + constructor( id: number, routeId: number, diff --git a/tests/unit/ClientBuilder.ts b/tests/unit/ClientBuilder.ts new file mode 100644 index 0000000..9fc7a54 --- /dev/null +++ b/tests/unit/ClientBuilder.ts @@ -0,0 +1,18 @@ +import MetlinkHttpClient from "../../src/MetlinkHttpClient"; +import {AxiosAdapter} from "../../src/domain/httpclient/AxiosAdapter"; +import {ResponseDataDecorator} from "../../src/ResponseDataDecorator"; +import {MetlinkHttpClientInterface} from "../../src/Contracts"; + +export class ClientBuilder { + public static getHttpClient(client: Axios.AxiosInstance): MetlinkHttpClientInterface { + const adapter: AxiosAdapter = new AxiosAdapter(client); + + return new MetlinkHttpClient(adapter); + } + + public static getHttpClientWithResponseDataDecorator(client: Axios.AxiosInstance): MetlinkHttpClientInterface { + const adapter: AxiosAdapter = new AxiosAdapter(client); + + return new ResponseDataDecorator(new MetlinkHttpClient(adapter)); + } +} \ No newline at end of file diff --git a/tests/unit/ResponseDataDecorator/Gtfs-rt/ServiceAlerts.test.ts b/tests/unit/ResponseDataDecorator/Gtfs-rt/ServiceAlerts.test.ts new file mode 100644 index 0000000..27b537c --- /dev/null +++ b/tests/unit/ResponseDataDecorator/Gtfs-rt/ServiceAlerts.test.ts @@ -0,0 +1,235 @@ +import axios from 'axios'; +import MockAdapter from "axios-mock-adapter"; + +const mock: MockAdapter = new MockAdapter(axios); + +describe.skip("Response Data Decorator: GTFS-RT: Service alerts", () => { + + afterEach(function () { + mock.reset(); + }); + + + function getSchema(): {} { + return { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "array", + "items": { + "type": "object", + "properties": { + "header": { + "type": "object", + "properties": { + "gtfsRealtimeVersion": { + "type": "string" + }, + "incrementality": { + "type": "integer" + }, + "timestamp": { + "type": "integer" + } + }, + "required": ["gtfsRealtimeVersion", "incrementality", "timestamp"] + }, + "entity": { + "type": "array", + "items": { + "type": "object", + "properties": { + "alert": { + "type": "object", + "properties": { + "active_period": { + "type": "array", + "items": { + "type": "object", + "properties": { + "start": { + "type": "integer" + }, + "end": { + "type": "integer" + } + }, + "required": ["start", "end"] + } + }, + "effect": { + "type": "string" + }, + "cause": { + "type": "string" + }, + "description_text": { + "type": "object", + "properties": { + "translation": { + "type": "array", + "items": { + "type": "object", + "properties": { + "language": { + "type": "string" + }, + "text": { + "type": "string" + } + }, + "required": ["language", "text"] + } + } + }, + "required": ["translation"] + }, + "header_text": { + "type": "object", + "properties": { + "translation": { + "type": "array", + "items": { + "type": "object", + "properties": { + "language": { + "type": "string" + }, + "text": { + "type": "string" + } + }, + "required": ["language", "text"] + } + } + }, + "required": ["translation"] + }, + "informed_entity": { + "type": "array", + "items": { + "type": "object", + "properties": { + "route_id": { + "type": "string" + }, + "route_type": { + "type": "integer" + }, + "trip": { + "type": "object", + "properties": { + "start_time": { + "type": "string" + }, + "description": { + "type": "string" + }, + "trip_id": { + "type": "string" + }, + "direction_id": { + "type": "integer" + }, + "route_id": { + "type": "number" + }, + "start_date": { + "type": "string" + } + }, + "required": ["start_time", "description", "trip_id", "direction_id", "route_id", "start_date"] + } + }, + "required": ["route_id", "route_type", "trip"] + } + }, + "severity_level": { + "type": "string" + } + }, + "required": ["active_period", "effect", "cause", "description_text", "header_text", "informed_entity", "severity_level"] + }, + "id": { + "type": "string" + }, + "timestamp": { + "type": "string" + } + }, + "required": ["alert", "id", "timestamp"] + } + } + }, + "required": ["header", "entity"] + } + } + } + + const dataSet = [ + [ + [ + { + "header": { + "gtfsRealtimeVersion": "2.0", + "incrementality": 0, + "timestamp": 1726282687 + }, + "entity": [ + { + "alert": { + "active_period": [ + { + "start": 1714071600, + "end": 1734635400 + } + ], + "effect": "STOP_MOVED", + "cause": "OTHER_CAUSE", + "description_text": { + "translation": [ + { + "language": "en", + "text": "To minimise delays caused by Wairarapa services, the 7:00am, 7:40am, and 8:00am services from Upper Hutt to Wellington will depart from Platform 2 at Wallaceville and Trentham stations. This is an ongoing permanent change. Announcements will be made where possible." + } + ] + }, + "header_text": { + "translation": [ + { + "language": "en", + "text": "The 7:00am, 7:40am, and 8:00am weekday services from Upper Hutt to Wellington will depart from Platform 2 at Wallaceville and Trentham stations." + } + ] + }, + "informed_entity": [ + { + "route_id": "5", + "route_type": 2, + "trip": { + "start_time": "07:00:00", + "description": "7:00am from Upper Hutt Station to Wellington Station", + "trip_id": "HVL__1__2611__RAIL__Rail_MTuWThF-XHol_20240428", + "direction_id": 1, + "route_id": 5, + "start_date": "20240508" + } + } + ], + "severity_level": "WARNING" + }, + "id": "140453", + "timestamp": "2024-04-24T13:33:25+1200" + } + ] + } + ] + ] + ]; + + function getPath(): string { + return "/gtfs-rt/servicealerts"; + } + + it.each(dataSet)("getServiceAlerts", async (mockData) => { + it.skip("Skip", function () {}); + }); +}); \ No newline at end of file diff --git a/tests/unit/ResponseDataDecorator/Gtfs-rt/TripUpdates.test.ts b/tests/unit/ResponseDataDecorator/Gtfs-rt/TripUpdates.test.ts new file mode 100644 index 0000000..88d0822 --- /dev/null +++ b/tests/unit/ResponseDataDecorator/Gtfs-rt/TripUpdates.test.ts @@ -0,0 +1,165 @@ +import axios from 'axios'; +import MockAdapter from "axios-mock-adapter"; + +const mock: MockAdapter = new MockAdapter(axios); + +describe.skip("Response Data Decorator: GTFS-RT: Trip updates", () => { + + afterEach(function () { + mock.reset(); + }); + + function getSchema(): {} { + return { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "header": { + "type": "object", + "properties": { + "gtfsRealtimeVersion": { + "type": "string" + }, + "incrementality": { + "type": "integer" + }, + "timestamp": { + "type": "integer" + } + }, + "required": ["gtfsRealtimeVersion", "incrementality", "timestamp"] + }, + "entity": { + "type": "array", + "items": { + "type": "object", + "properties": { + "trip_update": { + "type": "object", + "properties": { + "stop_time_update": { + "type": "object", + "properties": { + "schedule_relationship": { + "type": "integer" + }, + "stop_sequence": { + "type": "integer" + }, + "arrival": { + "type": "object", + "properties": { + "delay": { + "type": "integer" + }, + "time": { + "type": "integer" + } + }, + "required": ["delay", "time"] + }, + "stop_id": { + "type": "string" + } + }, + "required": ["schedule_relationship", "stop_sequence", "arrival", "stop_id"] + }, + "trip": { + "type": "object", + "properties": { + "start_time": { + "type": "string" + }, + "trip_id": { + "type": "string" + }, + "direction_id": { + "type": "integer" + }, + "route_id": { + "type": "integer" + }, + "schedule_relationship": { + "type": "integer" + }, + "start_date": { + "type": "string" + } + }, + "required": ["start_time", "trip_id", "direction_id", "route_id", "schedule_relationship", "start_date"] + }, + "vehicle": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + }, + "required": ["id"] + }, + "timestamp": { + "type": "integer" + } + }, + "required": ["stop_time_update", "trip", "vehicle", "timestamp"] + }, + "id": { + "type": "string" + } + }, + "required": ["trip_update", "id"] + } + } + }, + "required": ["header", "entity"] + } + } + + const dataSet = [ + [ + { + "header": { + "gtfsRealtimeVersion": "2.0", + "incrementality": 0, + "timestamp": 1726514766 + }, + "entity": [ + { + "trip_update": { + "stop_time_update": { + "schedule_relationship": 0, + "stop_sequence": 36, + "arrival": { + "delay": 237, + "time": 1726514769 + }, + "stop_id": "9242" + }, + "trip": { + "start_time": "06:55:00", + "trip_id": "110__0__103__TZM__501__4__501__4_20240825", + "direction_id": 0, + "route_id": 1100, + "schedule_relationship": 0, + "start_date": "20240917" + }, + "vehicle": { + "id": "3315" + }, + "timestamp": 1726514757 + }, + "id": "fb9742b0-b5c3-46ca-99cf-c4f24668607d" + } + ] + } + ] + ]; + + function getPath(): string { + return "/gtfs-rt/tripupdates"; + } + + it.each(dataSet)("GetGtfsRtTripUpdates", async (mockData) => { + it.skip("Skip", function () {}); + }); +}); \ No newline at end of file diff --git a/tests/unit/ResponseDataDecorator/Gtfs-rt/VehiclePositions.test.ts b/tests/unit/ResponseDataDecorator/Gtfs-rt/VehiclePositions.test.ts new file mode 100644 index 0000000..f6d70ec --- /dev/null +++ b/tests/unit/ResponseDataDecorator/Gtfs-rt/VehiclePositions.test.ts @@ -0,0 +1,153 @@ +import axios from 'axios'; +import MockAdapter from "axios-mock-adapter"; + +const mock: MockAdapter = new MockAdapter(axios); + +describe.skip("Response Data Decorator: GTFS-RT: Vehicle positions", () => { + + afterEach(function () { + mock.reset(); + }); + + function getSchema(): {} { + return { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "header": { + "type": "object", + "properties": { + "gtfsRealtimeVersion": { + "type": "string" + }, + "incrementality": { + "type": "integer" + }, + "timestamp": { + "type": "integer" + } + }, + "required": ["gtfsRealtimeVersion", "incrementality", "timestamp"] + }, + "entity": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "vehicle": { + "type": "object", + "properties": { + "trip": { + "type": "object", + "properties": { + "start_time": { + "type": "string" + }, + "trip_id": { + "type": "string" + }, + "direction_id": { + "type": "integer" + }, + "route_id": { + "type": "integer" + }, + "schedule_relationship": { + "type": "integer" + }, + "start_date": { + "type": "string" + } + }, + "required": ["start_time", "trip_id", "direction_id", "route_id", "schedule_relationship", "start_date"] + }, + "position": { + "type": "object", + "properties": { + "bearing": { + "type": "integer" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + } + }, + "required": ["bearing", "latitude", "longitude"] + }, + "occupancy_status": { + "type": "integer" + }, + "vehicle": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + }, + "required": ["id"] + }, + "timestamp": { + "type": "integer" + } + }, + "required": ["trip", "position", "occupancy_status", "vehicle", "timestamp"] + } + }, + "required": ["id", "vehicle"] + } + } + }, + "required": ["header", "entity"] + } + } + + const dataSet = [ + [ + { + "header": { + "gtfsRealtimeVersion": "2.0", + "incrementality": 0, + "timestamp": 1726515043 + }, + "entity": [ + { + "id": "258a7bb5-3ae7-4436-a7d5-340893394391", + "vehicle": { + "trip": { + "start_time": "07:15:00", + "trip_id": "4__1__112__NBM__7__5__7__5_20240825", + "direction_id": 1, + "route_id": 40, + "schedule_relationship": 0, + "start_date": "20240917" + }, + "position": { + "bearing": 282, + "latitude": -41.3181801, + "longitude": 174.7966614 + }, + "occupancy_status": 1, + "vehicle": { + "id": "1471" + }, + "timestamp": 1726515037 + } + } + ] + } + ] + ]; + + function getPath(): string { + return "/gtfs-rt/vehiclepositions"; + } + + it.each(dataSet)("GetGtfsRtVehiclePosition", async (mockData) => { + it.skip("Skip", function () {}); + }); +}); \ No newline at end of file diff --git a/tests/unit/ResponseDataDecorator/Gtfs/Agencies.test.ts b/tests/unit/ResponseDataDecorator/Gtfs/Agencies.test.ts new file mode 100644 index 0000000..22eb95e --- /dev/null +++ b/tests/unit/ResponseDataDecorator/Gtfs/Agencies.test.ts @@ -0,0 +1,76 @@ +import axios from 'axios'; +import MockAdapter from "axios-mock-adapter"; +import {MetlinkHttpClientInterface} from "../../../../src/Contracts"; +import {ClientBuilder} from "../../ClientBuilder"; +import {Agency} from "../../../../src/domain/gtfs/entity/Agency"; + +const mock: MockAdapter = new MockAdapter(axios); + +describe("Response Data Decorator: Agencies", () => { + + afterEach(function () { + mock.reset(); + }); + + function getSchema(): {} { + return { + type: "array", + items: { + type: "object", + properties: { + id: {type: "integer"}, + agency_id: {type: "string"}, + agency_name: {type: "string"}, + agency_timezone: {type: "string"}, + agency_url: {type: "string"}, + agency_lang: {type: "string"}, + agency_phone: {type: "string"}, + agency_fare_url: {type: "string"}, + }, + required: [ + "id", + "agency_id", + "agency_name", + "agency_timezone", + "agency_url", + "agency_lang", + "agency_phone", + "agency_fare_url" + ], + additionalProperties: false, + }, + }; + } + + const dataSet = [ + [ + [ + { + "id": 1, + "agency_id": "MADG", + "agency_name": "Madge Coachlines Limited", + "agency_timezone": "Pacific/Auckland", + "agency_url": "http://www.metlink.org.nz", + "agency_lang": "en", + "agency_phone": "", + "agency_fare_url": "http://www.metlink.org.nz/tickets-and-fares" + } + ] + ] + ]; + + function getPath(): string { + return "/gtfs/agency"; + } + + it.each(dataSet)("getGtfsAgencies", async (mockData) => { + mock.onGet(getPath()).replyOnce(200, mockData); + + const client: MetlinkHttpClientInterface = ClientBuilder.getHttpClientWithResponseDataDecorator(axios); + const response: Agency[] = await client.getGtfsAgencies(); + + response.forEach((entity, index) => { + expect(entity).toBeInstanceOf(Agency) + }) + }); +}); \ No newline at end of file diff --git a/tests/unit/ResponseDataDecorator/Gtfs/Calendar.test.ts b/tests/unit/ResponseDataDecorator/Gtfs/Calendar.test.ts new file mode 100644 index 0000000..8ebc7bf --- /dev/null +++ b/tests/unit/ResponseDataDecorator/Gtfs/Calendar.test.ts @@ -0,0 +1,116 @@ +import axios from 'axios'; +import MockAdapter from "axios-mock-adapter"; +import {MetlinkHttpClientInterface} from "../../../../src/Contracts"; +import {ClientBuilder} from "../../ClientBuilder"; +import {Calendar} from "../../../../src/domain/gtfs/entity/Calendar"; + +const mock: MockAdapter = new MockAdapter(axios); + +describe("Response Data Decorator: Calendar", () => { + + afterEach(function () { + mock.reset(); + }); + + function getSchema(): {} { + return { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "service_id": { + "type": "string" + }, + "monday": { + "type": "integer", + "enum": [0, 1] // Assuming 0 or 1 represent days of service (0 = no service, 1 = service) + }, + "tuesday": { + "type": "integer", + "enum": [0, 1] + }, + "wednesday": { + "type": "integer", + "enum": [0, 1] + }, + "thursday": { + "type": "integer", + "enum": [0, 1] + }, + "friday": { + "type": "integer", + "enum": [0, 1] + }, + "saturday": { + "type": "integer", + "enum": [0, 1] + }, + "sunday": { + "type": "integer", + "enum": [0, 1] + }, + "start_date": { + "type": "string", + "pattern": "^\\d{8}$" // Format YYYYMMDD + }, + "end_date": { + "type": "string", + "pattern": "^\\d{8}$" // Format YYYYMMDD + } + }, + "required": [ + "id", + "service_id", + "monday", + "tuesday", + "wednesday", + "thursday", + "friday", + "saturday", + "sunday", + "start_date", + "end_date" + ], + "additionalProperties": false + } + }; + } + + const dataSet = [ + [ + [ + { + id: 99, + service_id: '210_2_20240825', + monday: 0, + tuesday: 0, + wednesday: 0, + thursday: 0, + friday: 0, + saturday: 0, + sunday: 0, + start_date: '20240825', + end_date: '20240928' + }, + ] + ] + ]; + + function getPath(): string { + return "/gtfs/calendar"; + } + + it.each(dataSet)("getGtfsCalendar", async (mockData) => { + mock.onGet(getPath()).replyOnce(200, mockData); + + const client: MetlinkHttpClientInterface = ClientBuilder.getHttpClientWithResponseDataDecorator(axios); + const response: Calendar[] = await client.getGtfsCalendar(); + + response.forEach((entity) => { + expect(entity).toBeInstanceOf(Calendar) + }) + }); +}); \ No newline at end of file diff --git a/tests/unit/ResponseDataDecorator/Gtfs/CalendarDates.test.ts b/tests/unit/ResponseDataDecorator/Gtfs/CalendarDates.test.ts new file mode 100644 index 0000000..757aebb --- /dev/null +++ b/tests/unit/ResponseDataDecorator/Gtfs/CalendarDates.test.ts @@ -0,0 +1,68 @@ +import axios from 'axios'; +import MockAdapter from "axios-mock-adapter"; +import {MetlinkHttpClientInterface} from "../../../../src/Contracts"; +import {ClientBuilder} from "../../ClientBuilder"; +import {CalendarDate} from "../../../../src/domain/gtfs/entity/CalendarDate"; + +const mock: MockAdapter = new MockAdapter(axios); + +describe("Response Data Decorator: Calendar Dates", () => { + + afterEach(function () { + mock.reset(); + }); + + function getSchema(): {} { + return { + type: "array", + items: { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "service_id": { + "type": "string" + }, + "date": { + "type": "string", + "pattern": "^\\d{8}$" // Format YYYYMMDD + }, + "exception_type": { + "type": "integer", + } + }, + "required": ["id", "service_id", "date", "exception_type"], + "additionalProperties": false + } + }; + } + + const dataSet = [ + [ + [ + { + "id": 99, + "service_id": "612_20240825", + "date": "20240919", + "exception_type": 1 + } + ] + ] + ]; + + function getPath(): string { + return "/gtfs/calendar_dates"; + } + + it.each(dataSet)("getGtfsCalendarDates", async (mockData) => { + mock.onGet(getPath()).replyOnce(200, mockData); + + const client: MetlinkHttpClientInterface = ClientBuilder.getHttpClientWithResponseDataDecorator(axios); + const response: CalendarDate[] = await client.getGtfsCalendarDates(); + + response.forEach((entity) => { + expect(entity).toBeInstanceOf(CalendarDate) + }); + }); +}); \ No newline at end of file diff --git a/tests/unit/ResponseDataDecorator/Gtfs/FeedInfo.test.ts b/tests/unit/ResponseDataDecorator/Gtfs/FeedInfo.test.ts new file mode 100644 index 0000000..dc5611e --- /dev/null +++ b/tests/unit/ResponseDataDecorator/Gtfs/FeedInfo.test.ts @@ -0,0 +1,90 @@ +import axios from 'axios'; +import MockAdapter from "axios-mock-adapter"; +import {MetlinkHttpClientInterface} from "../../../../src/Contracts"; +import {ClientBuilder} from "../../ClientBuilder"; +import {Feed} from "../../../../src/domain/gtfs/entity/Feed"; + +const mock: MockAdapter = new MockAdapter(axios); + +describe("Response Data Decorator: Feed info", () => { + + afterEach(function () { + mock.reset(); + }); + + function getSchema(): {} { + return { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "feed_publisher_name": { + "type": "string" + }, + "feed_publisher_url": { + "type": "string", + }, + "feed_lang": { + "type": "string" + }, + "feed_start_date": { + "type": "string", + "pattern": "^\\d{8}$" // Format YYYYMMDD + }, + "feed_end_date": { + "type": "string", + "pattern": "^\\d{8}$" // Format YYYYMMDD + }, + "feed_version": { + "type": "string" + } + }, + "required": [ + "id", + "feed_publisher_name", + "feed_publisher_url", + "feed_lang", + "feed_start_date", + "feed_end_date", + "feed_version" + ], + "additionalProperties": false + } + }; + } + + const dataSet = [ + [ + [ + { + id: 1, + feed_publisher_name: 'publisher name', + feed_publisher_url: 'link', + feed_lang: 'en', + feed_start_date: '20240825', + feed_end_date: '20241012', + feed_version: 'Version' + } + ] + + ] + ]; + + function getPath(): string { + return "/gtfs/feed_info"; + } + + it.each(dataSet)("getGtfsFeedInfo", async (mockData) => { + mock.onGet(getPath()).replyOnce(200, mockData); + + const client: MetlinkHttpClientInterface = ClientBuilder.getHttpClientWithResponseDataDecorator(axios); + const response: Feed[] = await client.getGtfsFeedInfo(); + + response.forEach((entity) => { + expect(entity).toBeInstanceOf(Feed) + }); + }); +}); \ No newline at end of file diff --git a/tests/unit/ResponseDataDecorator/Gtfs/Routes.test.ts b/tests/unit/ResponseDataDecorator/Gtfs/Routes.test.ts new file mode 100644 index 0000000..d560b92 --- /dev/null +++ b/tests/unit/ResponseDataDecorator/Gtfs/Routes.test.ts @@ -0,0 +1,121 @@ +import axios from 'axios'; +import MockAdapter from "axios-mock-adapter"; +import {MetlinkHttpClientInterface} from "../../../../src/Contracts"; +import {ClientBuilder} from "../../ClientBuilder"; +import {Route} from "../../../../src/domain/gtfs/entity/Route"; + +const mock: MockAdapter = new MockAdapter(axios); + +describe("Response Data Decorator: Routes", () => { + + afterEach(function () { + mock.reset(); + }); + + function getSchema(): {} { + return { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "route_id": { + "type": "string" + }, + "agency_id": { + "type": "string" + }, + "route_short_name": { + "type": "string" + }, + "route_long_name": { + "type": "string" + }, + "route_desc": { + "type": "string" + }, + "route_type": { + "type": "integer" + }, + "route_color": { + "type": "string", + "pattern": "^[0-9a-fA-F]{6}$" // Hex color code without the '#' + }, + "route_text_color": { + "type": "string", + "pattern": "^[0-9a-fA-F]{6}$" // Hex color code without the '#' + }, + "route_url": { + "type": "string" + }, + "route_sort_order": { + "type": "integer" + } + }, + "required": [ + "id", + "route_id", + "agency_id", + "route_short_name", + "route_long_name", + "route_desc", + "route_type", + "route_color", + "route_text_color", + "route_url", + "route_sort_order" + ], + "additionalProperties": false + } + } + } + + const dataSet = [ + [ + [ + { + "id": 9, + "route_id": "10", + "agency_id": "TZM", + "route_short_name": "1", + "route_long_name": "Johnsonville West/Churton Park/Grenada Village - Island Bay", + "route_desc": "Island Bay - Johnsonville West/Churton Park/Grenada Village", + "route_type": 3, + "route_color": "e31837", + "route_text_color": "ffffff", + "route_url": "", + "route_sort_order": 10 + } + ] + + ] + ]; + + function getPath(): string { + return "/gtfs/routes"; + } + + it.each(dataSet)("getGtfsRoutes", async (mockData) => { + mock.onGet(getPath()).replyOnce(200, mockData); + + const client: MetlinkHttpClientInterface = ClientBuilder.getHttpClientWithResponseDataDecorator(axios); + const response:Route[] = await client.getGtfsRoutes(null); + + response.forEach((entity) => { + expect(entity).toBeInstanceOf(Route) + }); + }); + + it.each(dataSet)("getRouteById", async (mockData) => { + mock.onGet(getPath()).replyOnce(200, mockData); + + const client: MetlinkHttpClientInterface = ClientBuilder.getHttpClientWithResponseDataDecorator(axios); + const response: Route[] = await client.getGtfsRoutes("1100"); + + response.forEach((entity) => { + expect(entity).toBeInstanceOf(Route) + }); + }); +}); \ No newline at end of file diff --git a/tests/unit/ResponseDataDecorator/Gtfs/Shapes.test.ts b/tests/unit/ResponseDataDecorator/Gtfs/Shapes.test.ts new file mode 100644 index 0000000..e8e2aef --- /dev/null +++ b/tests/unit/ResponseDataDecorator/Gtfs/Shapes.test.ts @@ -0,0 +1,82 @@ +import axios from 'axios'; +import MockAdapter from "axios-mock-adapter"; +import {MetlinkHttpClientInterface} from "../../../../src/Contracts"; +import {ClientBuilder} from "../../ClientBuilder"; +import {Shape} from "../../../../src/domain/gtfs/entity/Shape"; + +const mock: MockAdapter = new MockAdapter(axios); + +describe("Response Data Decorator: Shapes", () => { + + afterEach(function () { + mock.reset(); + }); + + function getSchema(): {} { + return { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "shape_id": { + "type": "string" + }, + "shape_pt_lat": { + "type": "number" + }, + "shape_pt_lon": { + "type": "number" + }, + "shape_pt_sequence": { + "type": "integer" + }, + "shape_dist_traveled": { + "type": "number" + } + }, + "required": [ + "id", + "shape_id", + "shape_pt_lat", + "shape_pt_lon", + "shape_pt_sequence", + "shape_dist_traveled" + ], + "additionalProperties": false + } + }; + } + + const dataSet = [ + [ + [ + { + "id": 92441, + "shape_id": "[@364.0.17527449@]1_20240825", + "shape_pt_lat": -41.2091982, + "shape_pt_lon": 174.9050033, + "shape_pt_sequence": 0, + "shape_dist_traveled": 0 + } + ] + ] + ]; + + function getPath(): string { + return "/gtfs/shapes"; + } + + it.each(dataSet)("getGtfsShapes", async (mockData) => { + mock.onGet(getPath()).replyOnce(200, mockData); + + const client: MetlinkHttpClientInterface = ClientBuilder.getHttpClientWithResponseDataDecorator(axios); + const response:Shape[] = await client.getGtfsShapes("[@364.0.17527449@]1_20240825"); + + response.forEach((entity) => { + expect(entity).toBeInstanceOf(Shape) + }); + }); +}); \ No newline at end of file diff --git a/tests/unit/ResponseDataDecorator/Gtfs/StopTimes.test.ts b/tests/unit/ResponseDataDecorator/Gtfs/StopTimes.test.ts new file mode 100644 index 0000000..1455216 --- /dev/null +++ b/tests/unit/ResponseDataDecorator/Gtfs/StopTimes.test.ts @@ -0,0 +1,110 @@ +import axios from 'axios'; +import MockAdapter from "axios-mock-adapter"; +import {MetlinkHttpClientInterface} from "../../../../src/Contracts"; +import {ClientBuilder} from "../../ClientBuilder"; +import {StopTime} from "../../../../src/domain/gtfs/entity/StopTime"; + +const mock: MockAdapter = new MockAdapter(axios); + +describe("Response Data Decorator: Stop times", () => { + + afterEach(function () { + mock.reset(); + }); + + function getSchema(): {} { + return { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "trip_id": { + "type": "string" + }, + "arrival_time": { + "type": "string", + "pattern": "^\\d{2}:\\d{2}:\\d{2}$" // Format HH:MM:SS + }, + "departure_time": { + "type": "string", + "pattern": "^\\d{2}:\\d{2}:\\d{2}$" // Format HH:MM:SS + }, + "stop_id": { + "type": "string" + }, + "stop_sequence": { + "type": "integer" + }, + "shape_dist_traveled": { + "type": "number" + }, + "stop_headsign": { + "type": "string" + }, + "pickup_type": { + "type": "integer", + }, + "drop_off_type": { + "type": "integer", + }, + "timepoint": { + "type": "string", + } + }, + "required": [ + "id", + "trip_id", + "arrival_time", + "departure_time", + "stop_id", + "stop_sequence", + "shape_dist_traveled", + "stop_headsign", + "pickup_type", + "drop_off_type", + "timepoint" + ], + "additionalProperties": false + } + } + } + + const dataSet = [ + [ + [ + { + "id": 1, + "trip_id": "60__0__439__MNM__2071__1__2071__1_20240825", + "arrival_time": "16:58:00", + "departure_time": "16:58:00", + "stop_id": "3000", + "stop_sequence": 0, + "shape_dist_traveled": 0, + "stop_headsign": "Porirua", + "pickup_type": 0, + "drop_off_type": 1, + "timepoint": "1" + } + ] + ] + ]; + + function getPath(): string + { + return "/gtfs/shop_times"; + } + + it.each(dataSet)("getGtfsStopTimes", async (mockData) => { + mock.onGet(getPath()).replyOnce(200, mockData); + + const client: MetlinkHttpClientInterface = ClientBuilder.getHttpClientWithResponseDataDecorator(axios); + const response: StopTime[] = await client.getGtfsStopTimes("60__0__439__MNM__2071__1__2071__1_20240825"); + + response.forEach((entity) => { + expect(entity).toBeInstanceOf(StopTime) + }); + }); +}); \ No newline at end of file diff --git a/tests/unit/ResponseDataDecorator/Gtfs/Stops.test.ts b/tests/unit/ResponseDataDecorator/Gtfs/Stops.test.ts new file mode 100644 index 0000000..c787169 --- /dev/null +++ b/tests/unit/ResponseDataDecorator/Gtfs/Stops.test.ts @@ -0,0 +1,112 @@ +import axios from 'axios'; +import MockAdapter from "axios-mock-adapter"; +import {MetlinkHttpClientInterface} from "../../../../src/Contracts"; +import {ClientBuilder} from "../../ClientBuilder"; +import {Stop} from "../../../../src/domain/gtfs/entity/Stop"; + +const mock: MockAdapter = new MockAdapter(axios); + +describe("Response Data Decorator: Stops", () => { + + afterEach(function () { + mock.reset(); + }); + + function getSchema(): {} { + return { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "stop_id": { + "type": "string" + }, + "stop_code": { + "type": "string" + }, + "stop_name": { + "type": "string" + }, + "stop_desc": { + "type": "string" + }, + "zone_id": { + "type": "string" + }, + "stop_lat": { + "type": "number" + }, + "stop_lon": { + "type": "number" + }, + "location_type": { + "type": "integer" + }, + "parent_station": { + "type": "string" + }, + "stop_url": { + "type": "string" + }, + "stop_timezone": { + "type": "string" + } + }, + "required": [ + "id", + "stop_id", + "stop_code", + "stop_name", + "stop_desc", + "zone_id", + "stop_lat", + "stop_lon", + "location_type", + "parent_station", + "stop_url", + "stop_timezone" + ], + "additionalProperties": false + } + } + } + + const dataSet = [ + [ + [ + { + "id": 1, + "stop_id": "7951", + "stop_code": "7951", + "stop_name": "Buckley Road (near 108)", + "stop_desc": "", + "zone_id": "3", + "stop_lat": -41.33689713, + "stop_lon": 174.7827608, + "location_type": 0, + "parent_station": "", + "stop_url": "", + "stop_timezone": "Pacific/Auckland" + } + ] + ] + ]; + + function getPath(): string { + return "/gtfs/stops"; + } + + it.each(dataSet)("getGtfsStops", async (mockData) => { + mock.onGet(getPath()).replyOnce(200, mockData); + + const client: MetlinkHttpClientInterface = ClientBuilder.getHttpClientWithResponseDataDecorator(axios); + const response:Stop[] = await client.getGtfsStops(null, null); + + response.forEach((entity) => { + expect(entity).toBeInstanceOf(Stop) + }); + }); +}); \ No newline at end of file diff --git a/tests/unit/ResponseDataDecorator/Gtfs/Transfers.test.ts b/tests/unit/ResponseDataDecorator/Gtfs/Transfers.test.ts new file mode 100644 index 0000000..79e377a --- /dev/null +++ b/tests/unit/ResponseDataDecorator/Gtfs/Transfers.test.ts @@ -0,0 +1,87 @@ +import axios from 'axios'; +import MockAdapter from "axios-mock-adapter"; +import {MetlinkHttpClientInterface} from "../../../../src/Contracts"; +import {ClientBuilder} from "../../ClientBuilder"; +import {Transfer} from "../../../../src/domain/gtfs/entity/Transfer"; + +const mock: MockAdapter = new MockAdapter(axios); + +describe("Response Data Decorator: Transfers", () => { + + afterEach(function () { + mock.reset(); + }); + + function getSchema(): {} { + return { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "from_stop_id": { + "type": "string" + }, + "to_stop_id": { + "type": "string" + }, + "transfer_type": { + "type": "string" + }, + "min_transfer_time": { + "type": "string" + }, + "from_trip_id": { + "type": "string" + }, + "to_trip_id": { + "type": "string" + } + }, + "required": [ + "id", + "from_stop_id", + "to_stop_id", + "transfer_type", + "min_transfer_time", + "from_trip_id", + "to_trip_id" + ], + "additionalProperties": false + } + } + } + + const dataSet = [ + [ + [ + { + "id": 1, + "from_stop_id": "9416", + "to_stop_id": "SILV", + "transfer_type": "2", + "min_transfer_time": "240", + "from_trip_id": "115__0__421__TZM__508__3__508__3_20240825", + "to_trip_id": "HVL__1__3853__RAIL__Rail_SaSu+Hol_20240825" + } + ] + ] + ]; + + function getPath(): string { + return "/gtfs/transfers"; + } + + it.each(dataSet)("getGtfsTransfers", async (mockData) => { + mock.onGet(getPath()).replyOnce(200, mockData); + + const client: MetlinkHttpClientInterface = ClientBuilder.getHttpClientWithResponseDataDecorator(axios); + const response:Transfer[] = await client.getGtfsTransfers(); + + response.forEach((entity) => { + expect(entity).toBeInstanceOf(Transfer) + }); + }); +}); \ No newline at end of file diff --git a/tests/unit/ResponseDataDecorator/Gtfs/Trips.test.ts b/tests/unit/ResponseDataDecorator/Gtfs/Trips.test.ts new file mode 100644 index 0000000..8fe4c58 --- /dev/null +++ b/tests/unit/ResponseDataDecorator/Gtfs/Trips.test.ts @@ -0,0 +1,118 @@ +import axios from 'axios'; +import MockAdapter from "axios-mock-adapter"; +import {MetlinkHttpClientInterface} from "../../../../src/Contracts"; +import {ClientBuilder} from "../../ClientBuilder"; +import {Trip} from "../../../../src/domain/gtfs/entity/Trip"; + +const mock: MockAdapter = new MockAdapter(axios); + +describe("Response Data Decorator: Trips", () => { + + afterEach(function () { + mock.reset(); + }); + + function getSchema(): {} { + return { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "route_id": { + "type": "integer" + }, + "service_id": { + "type": "string" + }, + "trip_id": { + "type": "string" + }, + "trip_headsign": { + "type": "string" + }, + "direction_id": { + "type": "integer" + }, + "block_id": { + "type": "string" + }, + "shape_id": { + "type": "string" + }, + "wheelchair_accessible": { + "type": "integer" + }, + "bikes_allowed": { + "type": "integer" + }, + "origin_stop_id": { + "type": "string" + }, + "destination_stop_id": { + "type": "string" + } + }, + "required": [ + "id", + "route_id", + "service_id", + "trip_id", + "trip_headsign", + "direction_id", + "block_id", + "shape_id", + "wheelchair_accessible", + "bikes_allowed", + "origin_stop_id", + "destination_stop_id" + ], + "additionalProperties": false + } + } + } + + const dataSet = [ + [ + [ + { + "id": 1, + "route_id": 600, + "service_id": "2071_1_20240825", + "trip_id": "60__0__439__MNM__2071__1__2071__1_20240825", + "trip_headsign": "", + "direction_id": 0, + "block_id": "", + "shape_id": "[@356.0.29339884@]2_20240825", + "wheelchair_accessible": 0, + "bikes_allowed": 2, + "origin_stop_id": "3000", + "destination_stop_id": "2002" + } + ] + ] + ]; + + function getPath(): string { + return "/gtfs/trips"; + } + + it.each(dataSet)("getGtfsTrips", async (mockData) => { + mock.onGet(getPath()).replyOnce(200, mockData); + + const client: MetlinkHttpClientInterface = ClientBuilder.getHttpClientWithResponseDataDecorator(axios); + const response: Trip[] = await client.getGtfsTrips( + null, + null, + null, + null, + null, + ); + + response.forEach((entity) => { + expect(entity).toBeInstanceOf(Trip) + }); + }); +}); \ No newline at end of file diff --git a/tests/unit/ResponseDataDecorator/StopPredictions.test.ts b/tests/unit/ResponseDataDecorator/StopPredictions.test.ts new file mode 100644 index 0000000..a89d211 --- /dev/null +++ b/tests/unit/ResponseDataDecorator/StopPredictions.test.ts @@ -0,0 +1,184 @@ +import axios from 'axios'; +import MockAdapter from "axios-mock-adapter"; + +const mock: MockAdapter = new MockAdapter(axios); + +describe.skip("Response Data Decorator: Stop predictions", () => { + + afterEach(function (): void { + mock.reset(); + }); + + function getSchema(): {} { + return { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "farezone": { + "type": "string" + }, + "closed": { + "type": "boolean" + }, + "departures": { + "type": "array", + "items": { + "type": "object", + "properties": { + "stop_id": { + "type": "string" + }, + "service_id": { + "type": "string" + }, + "direction": { + "type": "string", + "enum": ["inbound", "outbound"] + }, + "operator": { + "type": "string" + }, + "origin": { + "type": "object", + "properties": { + "stop_id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": ["stop_id", "name"] + }, + "destination": { + "type": "object", + "properties": { + "stop_id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": ["stop_id", "name"] + }, + "delay": { + "type": "string", + "pattern": "^PT\\d+M\\d+S$" + }, + "vehicle_id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "arrival": { + "type": "object", + "properties": { + "aimed": { + "type": "string" + }, + "expected": { + "type": "string" + } + }, + "required": ["aimed", "expected"] + }, + "departure": { + "type": "object", + "properties": { + "aimed": { + "type": "string" + }, + "expected": { + "type": "string" + } + }, + "required": ["aimed", "expected"] + }, + "status": { + "type": "string", + "enum": ["on time", "delayed", "cancelled"] + }, + "monitored": { + "type": "boolean" + }, + "wheelchair_accessible": { + "type": "boolean" + }, + "trip_id": { + "type": "string" + } + }, + "required": [ + "stop_id", + "service_id", + "direction", + "operator", + "origin", + "destination", + "delay", + "vehicle_id", + "name", + "arrival", + "departure", + "status", + "monitored", + "wheelchair_accessible", + "trip_id" + ] + } + } + }, + "required": ["farezone", "closed", "departures"] + } + } + + const dataSet = [ + [ + { + "farezone": "7", + "closed": false, + "departures": [ + { + "stop_id": "WALL2", + "service_id": "HVL", + "direction": "outbound", + "operator": "RAIL", + "origin": { + "stop_id": "WELL1", + "name": "WgtnStn" + }, + "destination": { + "stop_id": "UPPE", + "name": "UPPE - All stops" + }, + "delay": "PT2M37S", + "vehicle_id": "4263", + "name": "WallacevilleStn", + "arrival": { + "aimed": "2024-09-17T07:51:00+12:00", + "expected": "2024-09-17T07:53:37+12:00" + }, + "departure": { + "aimed": "2024-09-17T07:51:00+12:00", + "expected": "2024-09-17T07:53:37+12:00" + }, + "status": "delayed", + "monitored": true, + "wheelchair_accessible": true, + "trip_id": "HVL__0__2616__RAIL__Rail_MTuWThF-XHol_20240825" + }, + ] + + } + ] + ]; + + function getPath(): string { + return "/stop-predictions"; + } + + it.each(dataSet)("getStopPredictions", async (mockData) => { + }); +}); \ No newline at end of file diff --git a/tests/unit/ResponseDataDecorator/TripCancellations.test.ts b/tests/unit/ResponseDataDecorator/TripCancellations.test.ts new file mode 100644 index 0000000..81f188d --- /dev/null +++ b/tests/unit/ResponseDataDecorator/TripCancellations.test.ts @@ -0,0 +1,93 @@ +import axios from 'axios'; +import MockAdapter from "axios-mock-adapter"; + +const mock: MockAdapter = new MockAdapter(axios); + +describe.skip("Response Data Decorator: Trip cancellations", () => { + + afterEach(function () { + mock.reset(); + }); + + function getSchema(): {} { + return { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "date_created": { + "type": "string", + }, + "date_updated": { + "type": "string", + }, + "trip_id": { + "type": "string" + }, + "route_id": { + "type": "integer" + }, + "trip_date_start": { + "type": "string", + }, + "trip_date_end": { + "type": "string" + }, + "direction_id": { + "type": "integer" + }, + "reinstated": { + "type": "integer", + "enum": [0, 1] + }, + "part_cancellation": { + "type": "integer", + "enum": [0, 1] + } + }, + "required": [ + "id", + "date_created", + "date_updated", + "trip_id", + "route_id", + "trip_date_start", + "trip_date_end", + "direction_id", + "reinstated", + "part_cancellation" + ] + } + } + } + + const dataSet = [ + [ + [ + { + "id": "ec196c26-d1ee-410d-bbaf-708763dcd10b", + "date_created": "2024-09-17 07:29:07", + "date_updated": "2024-09-17 07:53:48", + "trip_id": "1__1__134__TZM__224__1__224__1_20240825", + "route_id": 10, + "trip_date_start": "2024-09-17 08:03:00", + "trip_date_end": "2024-09-17 09:25:00", + "direction_id": 1, + "reinstated": 0, + "part_cancellation": 0 + }, + ] + ] + ]; + + function getPath(): string { + return "/trip-cancellations"; + } + + it.each(dataSet)("getTripCancellations", async (mockData) => { + }); +}); \ No newline at end of file