Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(signals): Added selectable entities behaviour by default #4718

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { patchState, signalStore } from '@ngrx/signals';
import {
addEntities,
withEntities,
selectEntity,
clearSelectedEntity,
} from '../../src';
import { User, user1, user2, user3 } from '../mocks';

describe('selectEntity', () => {
it('should clear the selectedEntity and selectedEntityId if an entity is selected and exists in the state', () => {
const Store = signalStore({ protectedState: false }, withEntities<User>());
const store = new Store();

patchState(store, addEntities([user1, user2, user3]));
patchState(store, selectEntity(user1.id));

expect(store.selectedId()).toBe(user1.id);
expect(store.selectedEntity()).toBe(user1);

patchState(store, clearSelectedEntity());

expect(store.selectedId()).toBe(null);
expect(store.selectedEntity()).toBe(null);
});

it('should clear the selectedEntity and selectedEntityId if an entity is selected and it does not exists in the state', () => {
const Store = signalStore({ protectedState: false }, withEntities<User>());
const store = new Store();

patchState(store, addEntities([user1, user2]));
patchState(store, selectEntity(user3.id));

expect(store.selectedId()).toBe(user3.id);
expect(store.selectedEntity()).toBe(null);

patchState(store, clearSelectedEntity());

expect(store.selectedId()).toBe(null);
expect(store.selectedEntity()).toBe(null);
});

it('should not change the state if an entity is not selected', () => {
const Store = signalStore({ protectedState: false }, withEntities<User>());
const store = new Store();

patchState(store, addEntities([user1, user2, user3]));

expect(store.selectedId()).toBe(null);
expect(store.selectedEntity()).toBe(null);

patchState(store, clearSelectedEntity());

expect(store.selectedId()).toBe(null);
expect(store.selectedEntity()).toBe(null);
});
});
49 changes: 49 additions & 0 deletions modules/signals/entities/spec/updaters/select-entity.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { patchState, signalStore, type } from '@ngrx/signals';
import {
addEntities,
addEntity,
withEntities,
selectEntity,
setEntities,
} from '../../src';
import { Todo, todo1, todo2, todo3, User, user1, user2, user3 } from '../mocks';

describe('selectEntity', () => {
it('should select an entity and return it if exists', () => {
const Store = signalStore({ protectedState: false }, withEntities<User>());
const store = new Store();

patchState(store, addEntities([user1, user2, user3]));
patchState(store, selectEntity(user1.id));

expect(store.selectedId()).toBe(user1.id);
expect(store.selectedEntity()).toBe(user1);
});

it('should select an entity and return null if it does not exists', () => {
const Store = signalStore({ protectedState: false }, withEntities<User>());
const store = new Store();

patchState(store, addEntities([user1, user2]));
patchState(store, selectEntity(user3.id));

expect(store.selectedId()).toBe(user3.id);
expect(store.selectedEntity()).toBe(null);
});

it('should return null if the selected entity does not exist and return the entity as soon as it is added to the state', () => {
const Store = signalStore({ protectedState: false }, withEntities<User>());
const store = new Store();

patchState(store, addEntities([user1, user2]));
patchState(store, selectEntity(user3.id));

expect(store.selectedId()).toBe(user3.id);
expect(store.selectedEntity()).toBe(null);

patchState(store, addEntity(user3));

expect(store.selectedId()).toBe(user3.id);
expect(store.selectedEntity()).toBe(user3);
});
});
83 changes: 58 additions & 25 deletions modules/signals/entities/spec/with-entities.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,41 @@ import { Todo, todo2, todo3, User, user1, user2 } from './mocks';
import { selectTodoId } from './helpers';

describe('withEntities', () => {
it('adds entity feature to the store', () => {
const Store = signalStore(
withEntities<User>(),
withMethods((store) => ({
addUsers(): void {
patchState(store, addEntities([user1, user2]));
},
}))
);
const store = new Store();

expect(isSignal(store.entityMap)).toBe(true);
expect(store.entityMap()).toEqual({});

expect(isSignal(store.ids)).toBe(true);
expect(store.ids()).toEqual([]);

expect(isSignal(store.entities)).toBe(true);
expect(store.entities()).toEqual([]);

store.addUsers();

expect(store.entityMap()).toEqual({ 1: user1, 2: user2 });
expect(store.ids()).toEqual([1, 2]);
expect(store.entities()).toEqual([user1, user2]);
describe('signle entity feature', () => {
it('adds entity feature to the store', () => {
const Store = signalStore(
withEntities<User>(),
withMethods((store) => ({
addUsers(): void {
patchState(store, addEntities([user1, user2]));
},
}))
);
const store = new Store();

expect(isSignal(store.entityMap)).toBe(true);
expect(store.entityMap()).toEqual({});

expect(isSignal(store.ids)).toBe(true);
expect(store.ids()).toEqual([]);

expect(isSignal(store.entities)).toBe(true);
expect(store.entities()).toEqual([]);

expect(isSignal(store.selectedId)).toBe(true);
expect(store.selectedId()).toEqual(null);

expect(isSignal(store.selectedEntity)).toBe(true);
expect(store.selectedEntity()).toEqual(null);

store.addUsers();

expect(store.entityMap()).toEqual({ 1: user1, 2: user2 });
expect(store.ids()).toEqual([1, 2]);
expect(store.entities()).toEqual([user1, user2]);
expect(store.selectedId()).toEqual(null);
expect(store.selectedEntity()).toEqual(null);
});
});

it('adds named entity feature to the store', () => {
Expand All @@ -55,11 +65,19 @@ describe('withEntities', () => {
expect(isSignal(store.userEntities)).toBe(true);
expect(store.userEntities()).toEqual([]);

expect(isSignal(store.userSelectedId)).toBe(true);
expect(store.userSelectedId()).toEqual(null);

expect(isSignal(store.userSelectedEntity)).toBe(true);
expect(store.userSelectedEntity()).toEqual(null);

store.addUsers();

expect(store.userEntityMap()).toEqual({ 2: user2, 1: user1 });
expect(store.userIds()).toEqual([2, 1]);
expect(store.userEntities()).toEqual([user2, user1]);
expect(store.userSelectedId()).toEqual(null);
expect(store.userSelectedEntity()).toEqual(null);
});

it('combines multiple entity features', () => {
Expand Down Expand Up @@ -99,13 +117,28 @@ describe('withEntities', () => {
expect(isSignal(store.todoEntities)).toBe(true);
expect(store.todoEntities()).toEqual([]);

expect(isSignal(store.selectedId)).toBe(true);
expect(store.selectedId()).toEqual(null);
expect(isSignal(store.todoSelectedId)).toBe(true);
expect(store.todoSelectedId()).toEqual(null);

expect(isSignal(store.selectedEntity)).toBe(true);
expect(store.selectedEntity()).toEqual(null);
expect(isSignal(store.todoSelectedEntity)).toBe(true);
expect(store.todoSelectedEntity()).toEqual(null);

store.addEntities();

expect(store.entityMap()).toEqual({ 2: user2, 1: user1 });
expect(store.ids()).toEqual([2, 1]);
expect(store.entities()).toEqual([user2, user1]);
expect(store.selectedId()).toEqual(null);
expect(store.selectedEntity()).toEqual(null);

expect(store.todoEntityMap()).toEqual({ y: todo2, z: todo3 });
expect(store.todoIds()).toEqual(['y', 'z']);
expect(store.todoEntities()).toEqual([todo2, todo3]);
expect(store.todoSelectedId()).toEqual(null);
expect(store.todoSelectedEntity()).toEqual(null);
});
});
Loading