PHP 8.2.30
Preview: resource-decorator.spec.js Size: 9.13 KB
//proc/thread-self/root/home/byroehnu/.trash/node_modules11/adminjs/lib/backend/decorators/resource/resource-decorator.spec.js

import sinon from 'sinon';
import { expect } from 'chai';
import ResourceDecorator from './resource-decorator.js';
import PropertyDecorator from '../property/property-decorator.js';
import AdminJS, { defaultOptions } from '../../../adminjs.js';
import resourceStub, { expectedResult } from '../../../../spec/backend/helpers/resource-stub.js';
const someID = 'someID';
const currentAdmin = {
  email: 'some@email.com',
  name: 'someName',
  otherValue: 'someOther-value'
};
const stubAdminJS = () => {
  const stubbedAdmin = sinon.createStubInstance(AdminJS);
  return Object.assign(stubbedAdmin, {
    translateProperty: sinon.stub().returns('translated property'),
    translateAction: sinon.stub().returns('translated action'),
    translateMessage: sinon.stub().returns('translate message'),
    options: {
      ...defaultOptions,
      rootPath: '/admin'
    }
  });
};
describe('ResourceDecorator', function () {
  let stubbedAdmin;
  let stubbedRecord;
  let stubbedResource;
  let args;
  beforeEach(function () {
    stubbedRecord = sinon.stub();
    stubbedResource = resourceStub();
    stubbedResource._decorated = {
      id: () => 'resourceId'
    };
    stubbedAdmin = stubAdminJS();
    args = {
      resource: stubbedResource,
      admin: stubbedAdmin
    };
  });
  afterEach(function () {
    sinon.restore();
  });
  describe('#getResourceName', function () {
    it('returns resource when name is not specified in options', function () {
      expect(new ResourceDecorator({
        ...args,
        options: {}
      }).getResourceName()).to.equal(someID);
    });
  });
  describe('#getNavigation', function () {
    it('returns custom name with icon when options were specified', function () {
      const options = {
        navigation: {
          name: 'someName',
          icon: 'someIcon',
          show: true
        }
      };
      expect(new ResourceDecorator({
        ...args,
        options
      }).getNavigation()).to.deep.equal(options.navigation);
    });
  });
  describe('#getProperties', function () {
    context('all properties are visible', function () {
      beforeEach(function () {
        sinon.stub(PropertyDecorator.prototype, 'isVisible').returns(true);
      });
      it('returns first n items when limit is given', function () {
        const max = 3;
        const decorator = new ResourceDecorator(args);
        expect(decorator.getProperties({
          where: 'list',
          max
        })).to.have.lengthOf(max);
      });
      it('returns all properties when limit is not given', function () {
        const decorator = new ResourceDecorator(args);
        expect(decorator.getProperties({
          where: 'list'
        })).to.have.lengthOf(expectedResult.properties.length);
      });
      it('returns only showProperties from options if they were given', function () {
        const path = expectedResult.properties[0].path();
        const decorator = new ResourceDecorator({
          ...args,
          options: {
            showProperties: [path]
          }
        });
        expect(decorator.getProperties({
          where: 'show'
        })).to.have.lengthOf(1);
      });
    });
  });
  describe('#resourceActions', function () {
    context('no action were specified in custom settings', function () {
      let decorator;
      beforeEach(function () {
        const options = {};
        decorator = new ResourceDecorator({
          ...args,
          options
        });
      });
      it('returns 2 default resource actions', function () {
        const actions = decorator.resourceActions(currentAdmin);
        const [action] = actions;
        expect(actions).to.have.lengthOf(2);
        expect(action).to.have.property('name', 'new');
      });
    });
  });
  describe('#getPropertyByKey', function () {
    let decorator;
    beforeEach(function () {
      decorator = new ResourceDecorator(args);
    });
    it('returns property by giving its key', function () {
      const propertyPath = expectedResult.properties[0].path();
      expect(decorator.getPropertyByKey(propertyPath)).to.be.an.instanceof(PropertyDecorator);
    });
    it('returns null when there is no property by given key', function () {
      expect(decorator.getPropertyByKey('some-unknown-name')).to.eq(null);
    });
    it('returns mixed property', function () {
      const propertyPath = expectedResult.properties.find(p => p.type() === 'mixed')?.path();
      expect(decorator.getPropertyByKey(propertyPath)).to.be.an.instanceof(PropertyDecorator);
    });
    it('returns nested property under mixed', function () {
      const property = expectedResult.properties.find(p => p.type() === 'mixed');
      const nested1Property = property?.subProperties().find(p => p.type() !== 'mixed');
      const path = [property.path(), nested1Property.path()].join('.');
      const decoratedProperty = decorator.getPropertyByKey(path);
      expect(decoratedProperty).to.be.an.instanceof(PropertyDecorator);
      expect(decoratedProperty.propertyPath).to.eq(path);
    });
    it('returns nested property under 2 level nested mixed', function () {
      const property = expectedResult.properties.find(p => p.type() === 'mixed');
      const nested1Property = property?.subProperties().find(p => p.type() === 'mixed');
      const nested2Property = nested1Property?.subProperties()[0];
      const path = [property.path(), nested1Property.path(), nested2Property.path()].join('.');
      const decoratedProperty = decorator.getPropertyByKey(path);
      expect(decoratedProperty).to.be.an.instanceof(PropertyDecorator);
      expect(decoratedProperty.propertyPath).to.eq(path);
    });
    it('returns property when it is an array', function () {
      const arrayProperty = expectedResult.properties.find(p => p.isArray());
      // checking of a property of first item in an array
      const path = [arrayProperty.path(), '0'].join('.');
      const decoratedProperty = decorator.getPropertyByKey(path);
      expect(decoratedProperty).to.be.an.instanceof(PropertyDecorator);
      expect(decoratedProperty.propertyPath).to.eq(arrayProperty.path());
    });
    it('returns property when it is an nested array', function () {
      const arrayProperty = expectedResult.properties.find(p => p.isArray() && p.type() === 'mixed');
      const nested1Property = arrayProperty?.subProperties()[0];

      // checking of a property of first item in an array
      const path = [arrayProperty.path(), '0', nested1Property.path()].join('.');
      const decoratedProperty = decorator.getPropertyByKey(path);
      expect(decoratedProperty).to.be.an.instanceof(PropertyDecorator);
      expect(decoratedProperty.propertyPath).to.eq([arrayProperty.path(), nested1Property.path()].join('.'));
    });
  });
  describe('#recordAction', function () {
    it('returns default actions', function () {
      const actions = new ResourceDecorator({
        ...args,
        options: {}
      }).recordActions(stubbedRecord, currentAdmin);
      expect(actions).to.have.lengthOf(3);
    });
    it('shows custom actions specified by the user', function () {
      const options = {
        actions: {
          customAction: {
            actionType: 'record'
          }
        }
      };
      const actions = new ResourceDecorator({
        ...args,
        options
      }).recordActions(stubbedRecord, currentAdmin);
      expect(actions).to.have.lengthOf(4);
    });
    it('hides the given action if user set isVisible to false', function () {
      const options = {
        actions: {
          show: {
            isVisible: false
          }
        }
      };
      const actions = new ResourceDecorator({
        ...args,
        options
      }).recordActions(stubbedRecord, currentAdmin);
      expect(actions).to.have.lengthOf(2);
    });
    it('passes properties to isVisible when it is a function', function () {
      const someRecord = {
        params: {
          param: 'someRecord'
        }
      };
      const options = {
        actions: {
          show: {
            isVisible: data => {
              // it passes current admin to the isVisible function
              expect(data.currentAdmin).to.deep.equal(currentAdmin);
              expect(data.resource.id).to.equal(stubbedResource.id);
              expect(data.action.name).to.equal('show');
              expect(data.record).to.equal(someRecord);
              return false;
            }
          }
        }
      };
      const actions = new ResourceDecorator({
        ...args,
        options
      }).recordActions(someRecord, currentAdmin);
      expect(actions).to.have.lengthOf(2);
    });
  });
  describe('#toJSON', function () {
    it('returns JSON representation of a resource', function () {
      const json = new ResourceDecorator(args).toJSON(currentAdmin);
      expect(json).to.have.keys('id', 'name', 'navigation', 'href', 'actions', 'titleProperty', 'resourceActions', 'listProperties', 'editProperties', 'showProperties', 'filterProperties', 'properties');
    });
    it('passes current admin to the resourceActions', function () {
      const resourceActionsSpy = sinon.spy(ResourceDecorator.prototype, 'resourceActions');
      new ResourceDecorator(args).toJSON(currentAdmin);
      expect(resourceActionsSpy).to.have.been.calledWith(currentAdmin);
    });
  });
});

Directory Contents

Dirs: 1 × Files: 4

Name Size Perms Modified Actions
utils DIR
- drwxr-xr-x 2026-02-28 00:31:40
Edit Download
120 B lrw-r--r-- 2026-02-28 00:31:40
Edit Download
8.76 KB lrw-r--r-- 2026-02-28 00:31:48
Edit Download
9.13 KB lrw-r--r-- 2026-02-28 00:31:48
Edit Download
10 B lrw-r--r-- 2026-02-28 00:31:48
Edit Download

If ZipArchive is unavailable, a .tar will be created (no compression).