Implement getRegionPokemonList with queryFn and related test cases

develop
Jason Zhu 2023-03-28 22:44:00 +11:00
parent 5c87c25620
commit f4da542ecd
11 changed files with 4293 additions and 0 deletions

View File

@ -114,5 +114,16 @@ describe('pokedexApi', () => {
// @ts-ignore // @ts-ignore
expect(pokemonListData?.previous).toBeUndefined(); expect(pokemonListData?.previous).toBeUndefined();
}); });
test('query getRegionPokemonList for kanto should return correct data in list', async () => {
await store.dispatch(
pokedexApi.endpoints.getRegionPokemonList.initiate('johto'),
);
const pokemonListData = pokedexApi.endpoints.getRegionPokemonList.select(
'johto',
)(store.getState()).data;
expect(pokemonListData).toHaveLength(19);
}, 100000000000);
}); });
}); });

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,36 @@
{
"areas": [
{
"name": "blackthorn-city-area",
"url": "https://pokeapi.co/api/v2/location-area/249/"
}
],
"game_indices": [
{
"game_index": 136,
"generation": {
"name": "generation-iv",
"url": "https://pokeapi.co/api/v2/generation/4/"
}
}
],
"id": 65,
"name": "blackthorn-city",
"names": [
{
"language": {
"name": "fr",
"url": "https://pokeapi.co/api/v2/language/5/"
},
"name": "Ebènelle"
},
{
"language": {
"name": "en",
"url": "https://pokeapi.co/api/v2/language/9/"
},
"name": "Blackthorn City"
}
],
"region": { "name": "johto", "url": "https://pokeapi.co/api/v2/region/2/" }
}

View File

@ -0,0 +1,40 @@
{
"areas": [
{
"name": "burned-tower-1f",
"url": "https://pokeapi.co/api/v2/location-area/212/"
},
{
"name": "burned-tower-b1f",
"url": "https://pokeapi.co/api/v2/location-area/213/"
}
],
"game_indices": [
{
"game_index": 206,
"generation": {
"name": "generation-iv",
"url": "https://pokeapi.co/api/v2/generation/4/"
}
}
],
"id": 66,
"name": "burned-tower",
"names": [
{
"language": {
"name": "fr",
"url": "https://pokeapi.co/api/v2/language/5/"
},
"name": "Tour Cendrée"
},
{
"language": {
"name": "en",
"url": "https://pokeapi.co/api/v2/language/9/"
},
"name": "Burned Tower"
}
],
"region": { "name": "johto", "url": "https://pokeapi.co/api/v2/region/2/" }
}

View File

@ -0,0 +1,74 @@
{
"id": 2,
"locations": [
{
"name": "blackthorn-city",
"url": "https://pokeapi.co/api/v2/location/65/"
},
{ "name": "burned-tower", "url": "https://pokeapi.co/api/v2/location/66/" }
],
"main_generation": {
"name": "generation-ii",
"url": "https://pokeapi.co/api/v2/generation/2/"
},
"name": "johto",
"names": [
{
"language": {
"name": "ja-Hrkt",
"url": "https://pokeapi.co/api/v2/language/1/"
},
"name": "ジョウト地方"
},
{
"language": {
"name": "ko",
"url": "https://pokeapi.co/api/v2/language/3/"
},
"name": "성도지방"
},
{
"language": {
"name": "fr",
"url": "https://pokeapi.co/api/v2/language/5/"
},
"name": "Johto"
},
{
"language": {
"name": "de",
"url": "https://pokeapi.co/api/v2/language/6/"
},
"name": "Johto"
},
{
"language": {
"name": "it",
"url": "https://pokeapi.co/api/v2/language/8/"
},
"name": "Johto"
},
{
"language": {
"name": "en",
"url": "https://pokeapi.co/api/v2/language/9/"
},
"name": "Johto"
}
],
"pokedexes": [
{ "name": "original-johto", "url": "https://pokeapi.co/api/v2/pokedex/3/" },
{ "name": "updated-johto", "url": "https://pokeapi.co/api/v2/pokedex/7/" }
],
"version_groups": [
{
"name": "gold-silver",
"url": "https://pokeapi.co/api/v2/version-group/3/"
},
{ "name": "crystal", "url": "https://pokeapi.co/api/v2/version-group/4/" },
{
"name": "heartgold-soulsilver",
"url": "https://pokeapi.co/api/v2/version-group/10/"
}
]
}

View File

@ -4,12 +4,17 @@ import {
pokeApiFullListFetchArgs, pokeApiFullListFetchArgs,
} from './paginationBaseQuery'; } from './paginationBaseQuery';
import { import {
AreaResponseData,
LocationResponseData,
PokemonListResponseData, PokemonListResponseData,
PokemonResponseData, PokemonResponseData,
RegionListResponseData, RegionListResponseData,
RegionResponseData, RegionResponseData,
TypeListResponseData, TypeListResponseData,
TypeResponseData, TypeResponseData,
PokemonListItem,
nameUrlPair,
PokemonList,
} from './types/api'; } from './types/api';
const pokeApiBaseQuery = async ( const pokeApiBaseQuery = async (
@ -54,6 +59,69 @@ export const pokedexApi = createApi({
getType: builder.query<TypeResponseData, number | string>({ getType: builder.query<TypeResponseData, number | string>({
query: IdOrName => ({ url: `type/${IdOrName}` }), query: IdOrName => ({ url: `type/${IdOrName}` }),
}), }),
getLocation: builder.query<LocationResponseData, number | string>({
query: IdOrName => ({ url: `location/${IdOrName}` }),
}),
getArea: builder.query<AreaResponseData, number | string>({
query: IdOrName => ({ url: `location-area/${IdOrName}` }),
}),
getRegionPokemonList: builder.query<PokemonListItem[], number | string>({
async queryFn(regionIdOrName, api) {
// Get region data
const regionData: RegionResponseData = await api
.dispatch(pokedexApi.endpoints.getRegion.initiate(regionIdOrName))
.unwrap();
// Get location data
const locationDataList: LocationResponseData[] = await Promise.all(
regionData.locations.map(location =>
api
.dispatch(
pokedexApi.endpoints.getLocation.initiate(location.name),
)
.unwrap(),
),
);
// Get area datas
const areaDataList: AreaResponseData[] = await Promise.all(
locationDataList
.flatMap(locationData => locationData.areas)
.map(area =>
api
.dispatch(pokedexApi.endpoints.getArea.initiate(area.name))
.unwrap(),
),
);
// Collect unique Pokemon
const uniquePokemonList = new Set<nameUrlPair>();
areaDataList.forEach(areaData => {
areaData.pokemon_encounters.forEach(pokemon => {
uniquePokemonList.add(pokemon.pokemon);
});
});
// Get Pokemon data
const pokemonDataList: PokemonListItem[] = await Promise.all(
Array.from(uniquePokemonList).map(pokemon =>
api
.dispatch(pokedexApi.endpoints.getPokemon.initiate(pokemon.name))
.unwrap()
.then(pokemonData => {
return {
name: pokemonData.name,
id: pokemonData.id,
type: pokemonData.types.map(type => type.type.name),
image: pokemonData.sprites.other.dream_world.front_default,
};
}),
),
);
return { data: Array.from(pokemonDataList) };
},
}),
}), }),
}); });
@ -64,4 +132,6 @@ export const {
useGetPokemonQuery, useGetPokemonQuery,
useGetRegionQuery, useGetRegionQuery,
useGetTypeQuery, useGetTypeQuery,
useGetAreaQuery,
useGetLocationQuery,
} = pokedexApi; } = pokedexApi;

View File

@ -1,17 +1,20 @@
import { createSlice } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit';
import type { PayloadAction } from '@reduxjs/toolkit'; import type { PayloadAction } from '@reduxjs/toolkit';
import { PokemonProps } from './Pokemon';
import type { RootState } from 'app/store'; import type { RootState } from 'app/store';
interface PokedexState { interface PokedexState {
selectedRegion: string; selectedRegion: string;
selectedType: string; selectedType: string;
selectedSort: string; selectedSort: string;
pokemonList: PokemonProps[];
} }
const initialState: PokedexState = { const initialState: PokedexState = {
selectedRegion: '', selectedRegion: '',
selectedType: '', selectedType: '',
selectedSort: '', selectedSort: '',
pokemonList: [],
}; };
export const pokedexSlice = createSlice({ export const pokedexSlice = createSlice({

View File

@ -12,6 +12,17 @@ export type PokemonListResponseData = ListResponse;
export type RegionListResponseData = ListResponse; export type RegionListResponseData = ListResponse;
export type TypeListResponseData = ListResponse; export type TypeListResponseData = ListResponse;
export interface PokemonListItem {
name: string;
id: number;
type: string[];
image: string;
}
export interface PokemonList {
PokemonList: PokemonListItem[];
}
export interface RegionResponseData { export interface RegionResponseData {
// many fields are ignored // many fields are ignored
id: number; id: number;
@ -58,4 +69,32 @@ export interface PokemonResponseData {
stats: StatItem[]; stats: StatItem[];
types: typeItem[]; types: typeItem[];
weight: number; weight: number;
sprites: {
back_default: string;
front_default: string;
other: {
dream_world: {
front_default: string;
};
};
};
}
export interface LocationResponseData {
// many fields are ignored
areas: nameUrlPair[];
id: number;
name: string;
region: nameUrlPair;
}
export interface PokemonEncounter {
// many fields are ignored
pokemon: nameUrlPair;
}
export interface AreaResponseData {
// many fields are ignored
id: number;
name: string;
pokemon_encounters: PokemonEncounter[];
} }

View File

@ -5,6 +5,12 @@ import regionList from 'features/Pokedex/__test__/responses/regionList.json';
import typeList from 'features/Pokedex/__test__/responses/typeList.json'; import typeList from 'features/Pokedex/__test__/responses/typeList.json';
import pokemonListPg1 from 'features/Pokedex/__test__/responses/pokemonListPage1.json'; import pokemonListPg1 from 'features/Pokedex/__test__/responses/pokemonListPage1.json';
import pokemonListPg2 from 'features/Pokedex/__test__/responses/pokemonListPage2.json'; import pokemonListPg2 from 'features/Pokedex/__test__/responses/pokemonListPage2.json';
import region_johto from 'features/Pokedex/__test__/responses/region_johto.json';
import location_blackthorn_city from 'features/Pokedex/__test__/responses/location_blackthorn-city.json';
import location_burned_tower from 'features/Pokedex/__test__/responses/location_burned-tower.json';
import area_blackthorn_city_area from 'features/Pokedex/__test__/responses/area_blackthorn-city-area.json';
import area_burned_tower_1f from 'features/Pokedex/__test__/responses/area_burned-tower-1f.json';
import area_burned_tower_b1f from 'features/Pokedex/__test__/responses/area_burned-tower-b1f.json';
export const handlers = [ export const handlers = [
// mock https://pokeapi.co/api/v2/region/1 // mock https://pokeapi.co/api/v2/region/1
@ -34,4 +40,24 @@ export const handlers = [
return res(ctx.json(pokemonListPg2)); return res(ctx.json(pokemonListPg2));
} }
}), }),
// getRegionPokemonList
rest.get('https://pokeapi.co/api/v2/region/johto', (req, res, ctx) => {
return res(ctx.json(region_johto));
}),
rest.get('https://pokeapi.co/api/v2/location/65', (req, res, ctx) => {
return res(ctx.json(location_blackthorn_city));
}),
rest.get('https://pokeapi.co/api/v2/location/66', (req, res, ctx) => {
return res(ctx.json(location_burned_tower));
}),
rest.get('https://pokeapi.co/api/v2/location-area/249', (req, res, ctx) => {
return res(ctx.json(area_blackthorn_city_area));
}),
rest.get('https://pokeapi.co/api/v2/location-area/212', (req, res, ctx) => {
return res(ctx.json(area_burned_tower_1f));
}),
rest.get('https://pokeapi.co/api/v2/location-area/213', (req, res, ctx) => {
return res(ctx.json(area_burned_tower_b1f));
}),
]; ];