|
1 | 1 | /* eslint-disable @typescript-eslint/ban-ts-comment */ |
2 | 2 | import { describe, it } from 'vitest' |
3 | 3 | import assert from 'assert' |
4 | | -import { feathers, Feathers, getServiceOptions, Id, version } from '../src/index.js' |
| 4 | +import { feathers, Feathers, getServiceOptions, Id, version, method } from '../src/index.js' |
5 | 5 |
|
6 | 6 | describe('Feathers application', () => { |
7 | 7 | it('initializes', () => { |
@@ -563,4 +563,86 @@ describe('Feathers application', () => { |
563 | 563 | }) |
564 | 564 | }) |
565 | 565 | }) |
| 566 | + |
| 567 | + describe('route conflicts', () => { |
| 568 | + it('throws when custom method path conflicts with another service custom method', () => { |
| 569 | + const app = feathers() |
| 570 | + |
| 571 | + class MessageService { |
| 572 | + @method({ args: ['id', 'params'], http: 'GET', path: ':id/status' }) |
| 573 | + async status(id: Id) { |
| 574 | + return { id, status: 'message' } |
| 575 | + } |
| 576 | + } |
| 577 | + |
| 578 | + class NotificationService { |
| 579 | + // Same path pattern - this would conflict with messages/:id/status |
| 580 | + @method({ args: ['id', 'params'], http: 'GET', path: ':id/status' }) |
| 581 | + async status(id: Id) { |
| 582 | + return { id, status: 'notification' } |
| 583 | + } |
| 584 | + } |
| 585 | + |
| 586 | + app.use('messages', new MessageService()) |
| 587 | + app.use('notifications', new NotificationService()) |
| 588 | + |
| 589 | + // These have different base paths, so they should NOT conflict |
| 590 | + assert.ok(app.service('messages')) |
| 591 | + assert.ok(app.service('notifications')) |
| 592 | + }) |
| 593 | + |
| 594 | + it('throws when custom method path conflicts with another service base path', () => { |
| 595 | + const app = feathers() |
| 596 | + |
| 597 | + // Register a nested service first |
| 598 | + app.use('messages/archived', { |
| 599 | + async find() { |
| 600 | + return [] |
| 601 | + } |
| 602 | + }) |
| 603 | + |
| 604 | + // Now try to register a service with a custom method that would conflict |
| 605 | + class MessageService { |
| 606 | + async find() { |
| 607 | + return [] |
| 608 | + } |
| 609 | + |
| 610 | + @method({ args: ['params'], http: 'GET', path: 'archived' }) |
| 611 | + async archived() { |
| 612 | + return [] |
| 613 | + } |
| 614 | + } |
| 615 | + |
| 616 | + assert.throws( |
| 617 | + () => app.use('messages', new MessageService()), |
| 618 | + /Path 'messages\/archived' for method 'archived' conflicts with another service/ |
| 619 | + ) |
| 620 | + }) |
| 621 | + |
| 622 | + it('allows different custom method paths on the same service', () => { |
| 623 | + const app = feathers() |
| 624 | + |
| 625 | + class MessageService { |
| 626 | + @method({ args: ['id', 'params'], http: 'GET', path: ':id/status' }) |
| 627 | + async status(id: Id) { |
| 628 | + return { id, status: 'active' } |
| 629 | + } |
| 630 | + |
| 631 | + @method({ args: ['id', 'params'], http: 'POST', path: ':id/archive' }) |
| 632 | + async archive(id: Id) { |
| 633 | + return { id, archived: true } |
| 634 | + } |
| 635 | + |
| 636 | + @method({ args: ['params'], http: 'GET', path: 'stats' }) |
| 637 | + async stats() { |
| 638 | + return { total: 100 } |
| 639 | + } |
| 640 | + } |
| 641 | + |
| 642 | + // Should not throw |
| 643 | + app.use('messages', new MessageService()) |
| 644 | + |
| 645 | + assert.ok(app.service('messages')) |
| 646 | + }) |
| 647 | + }) |
566 | 648 | }) |
0 commit comments