Search code examples
javascriptarraysclassprototype

JavaScript functionality to create roles with classes


I am having a task to implement a functionality to create roles in JS,and each role is defining by its type (Guest, User, Admin).

  1. Type Guest should have : a method which gets an array of tasks(constructor); a method which gets tasks id (the array index) and returns a task from the array of tasks(getTask) createTask should not be defined and changeType too
  2. Type User also should have constructor like at Guest,also a method getTask,and createTask -a method which adds a new task to the array of tasks changeType should not be defined.
  3. Type Admin should have constructor-a method which gets an array of guests and users;

getArray-a method which returns an array of guests and users

changeType-a method which gets a number (the array index) modifies the array item at the provided index (changes the object type from a guest to a user and otherwise and as a result, the tasks should migrated from one type to another), and returns a modified array of items

So,i created all classes and methods,but in the final when i test it with npm,i get the messages that :

  • Guest should not implement method createTask
  • Guest should not implement method changeType
  • User should not implement method changeType
  • Admin should change type of role from User to Guest

But when i introduce them in console in browser,everything works good,but i observed that when i write guest.createTask it shows that its undefined and doesnt throw an error,but i think i should get the error.

Here is my code:

class Task {
    constructor(name) {
        this.name = name;
    }
}
class Guest {
    constructor(tasks) {
        this.tasks = tasks;
    }
    getTask(index) {
        return this.tasks[index];
    }
}

class User {
    constructor(tasks) {
        this.tasks = tasks;
    }
    getTask(index) {
        return this.tasks[index];
    }
    createTask(tasks) {
        return this.tasks.push(tasks);
    }
}

class Admin {
    constructor(userGuestArray) {
        this.userGuestArray = userGuestArray;
    }
    getArray() {
        return this.userGuestArray;
    }

    changeType(index, replace, arr) {
        replace = this.userGuestArray;
        arr = this.userGuestArray[index];
        if (replace[index] = Guest) {
            replace[index] = new User(arr.tasks);

        }if (replace[index] = User){
            replace[index] = new Guest(arr.tasks);

        }

        return replace;
    }
}

And here is the code to test Guest class:

const guest = new Guest(
    [
      new Task('task name 1'),
      new Task('task name 2'),
      new Task('task name 3'),
    ]
  );
expect(guest.getTask(0).name).to.equal('task name 1');
expect(guest.getTask(2).name).to.equal('task name 3');
const guest = new Guest([]);
expect(guest.createTask).to.throw('method \'createTask\' is not defined');
expect(guest.changeType).to.throw('method \'changeType\' is not defined');

And below is for admin to change type role:

admin = new Admin([
              new Guest([]),
              new Guest([new Task('task name 1')]),
              new User([]),
              new User([new Task('task name 2')]),
        ]);
 it('should change type of role from Guest to User', () => {
        expect(admin.getArray()[0] instanceof Guest).to.equal(true);
        admin.changeType(0);
        expect(admin.getArray()[0] instanceof User).to.equal(true);
    });

    it('should change type of role from User to Guest', () => {
        expect(admin.getArray()[3] instanceof User).to.equal(true);
        admin.changeType(3);
        expect(admin.getArray()[3] instanceof Guest).to.equal(true);
        
    });

    it('should move tasks from Guest to User, when change role', () => {
        expect(admin.getArray()[1].getTask(0)).to.deep.equal({ name: 'task name 1'});
        admin.changeType(1);
        expect(admin.getArray()[1].getTask(0)).to.deep.equal({ name: 'task name 1'});
    });

Please help to fix the errors,i already burnt my brain.. I tried to make methods private,but i think i dont to it right and doesnt work.I dont know what to do anymore. PS: i am new to JS and trying to learn with this tasks.

This is the whole test script to understand the assignment :

const {Task, Guest, User, Admin} = require('../src');
const chai = require('chai');
const { expect } = chai;

describe('Guest', () => {
  it('should have method getTask', () => {
    const guest = new Guest(
        [
          new Task('task name 1'),
          new Task('task name 2'),
          new Task('task name 3'),
        ]
      );
      console.log(1,guest);
      expect(guest.getTask(0).name).to.equal('task name 1');
      console.log(2,guest.getTask(0).name);
      expect(guest.getTask(2).name).to.equal('task name 3');
      console.log(3,guest.getTask(2).name);
  });

  it('should not implement method createTask', () => {
    const guest = new Guest([]);
    console.log(4,guest);
    expect(guest.createTask).to.throw('method \'createTask\' is not defined');
    console.log(5,guest.createTask);
  });

  it('should not implement method changeType', () => {
    const guest = new Guest([]);
    console.log(6,guest);
    expect(guest.changeType).to.throw('method \'changeType\' is not defined');
    console.log(7,guest.changeType);
  });
});

describe('User', () => {
    let user;
    beforeEach(() => {
        user = new User(
            [
              new Task('task name 1'),
              new Task('task name 2'),
              new Task('task name 3'),
            ]
          );
    })
    console.log(8,user);
    it('should have method getTask', () => {
        expect(9,user.getTask(0).name).to.equal('task name 1');
        console.log(user.getTask(0).name)
        expect(10,user.getTask(2).name).to.equal('task name 3');
    });

    it('should have method createTask', () => {
        expect(user.getTask(0).name).to.equal('task name 1');
        console.log(11,user.getTask(0).name);
        expect(user.getTask(2).name).to.equal('task name 3');
        console.log(12,user.getTask(2).name);
        user.createTask(new Task('task name 4'))
        console.log(13,user.createTask(new Task('task name 4')));
        expect(user.getTask(3).name).to.equal('task name 4');
        console.log(14,user.getTask(3).name);
    });

    it('should not implement method changeType', () => {
        const user = new Guest([]);
        console.log(15,user);
        expect(user.changeType).to.throw('method \'changeType\' is not defined');
        console.log(16,user.changeType);
    });
});

describe('Admin', () => {
    let admin;
    beforeEach(() => {
        admin = new Admin([
              new Guest([]),
              new Guest([new Task('task name 1')]),
              new User([]),
              new User([new Task('task name 2')]),
        ]);
    })
    console.log(17,admin);
    it('should have method getArray', () => {
        expect(admin.getArray().length).to.equal(4);
    });
console.log(18,admin.getArray().length);
    it('should return instance of Guest as a first element by the method getArray', () => {
        expect(admin.getArray()[0]).to.deep.equal({ tasks: []});
    });
console.log(19,admin.getArray()[0]);
    it('should return instance of User as a third element by the method getArray', () => {
        expect(admin.getArray()[3]).to.deep.equal({ tasks: [{ name: 'task name 2'}]});
    });
console.log(20,(admin.getArray()[3]));
    it('should return array of roles by the method getArray', () => {
        expect(admin.getArray()).to.deep.equal([{ tasks: []}, { tasks: [{ name: 'task name 1'}]}, { tasks: []}, { tasks: [{ name: 'task name 2'}]}]);
    });
console.log(21,admin.getArray())
    it('should change type of role from Guest to User', () => {
        expect(admin.getArray()[0] instanceof Guest).to.equal(true);
        console.log(22,admin.getArray()[0] instanceof Guest);
        admin.changeType(0);
        console.log(23, admin.changeType(0));
        expect(admin.getArray()[0] instanceof User).to.equal(true);
        console.log(24,admin.getArray()[0] instanceof User);
    });

    it('should change type of role from User to Guest', () => {
        expect(admin.getArray()[3] instanceof User).to.equal(true);
        console.log(25,admin.getArray()[3] instanceof User);
        admin.changeType(3);
        console.log(26,admin.changeType(3));
        expect(admin.getArray()[3] instanceof Guest).to.equal(true);
        console.log(27,admin.getArray()[3] instanceof Guest)
    });

    it('should move tasks from Guest to User, when change role', () => {
        expect(admin.getArray()[1].getTask(0)).to.deep.equal({ name: 'task name 1'});
        console.log(28,admin.getArray()[1].getTask(0));
        admin.changeType(1);
        console.log(29,admin.changeType(1));
        expect(admin.getArray()[1].getTask(0)).to.deep.equal({ name: 'task name 1'});
        console.log(30,admin.getArray()[1].getTask(0));
    });

    
});

Dont pay attention to console logs,i tried to debug my code to see where is the error. Error log :

        <?xml version="1.0" encoding="UTF-8"?>
<testsuites name="Mocha Tests" time="0.0090" tests="13" failures="5">
  <testsuite name="Root Suite" timestamp="2021-11-06T12:36:46" tests="0" time="0.0000" failures="0">
  </testsuite>
  <testsuite name="Guest" timestamp="2021-11-06T12:36:46" tests="3" file="C:\Users\artio\Desktop\6 Classes\8.2.classes\test\index.js" time="0.0040" failures="2">
    <testcase name="Guest should have method getTask" time="0.0010" classname="should have method getTask">
    </testcase>
    <testcase name="Guest should not implement method createTask" time="0.0010" classname="should not implement method createTask">
      <failure message="expected undefined to be a function" type="AssertionError"><![CDATA[AssertionError: expected undefined to be a function
    at Context.<anonymous> (test\index.js:21:38)
    at processImmediate (internal/timers.js:439:21)]]></failure>
    </testcase>
    <testcase name="Guest should not implement method changeType" time="0.0000" classname="should not implement method changeType">
      <failure message="expected undefined to be a function" type="AssertionError"><![CDATA[AssertionError: expected undefined to be a function
    at Context.<anonymous> (test\index.js:26:38)
    at processImmediate (internal/timers.js:439:21)]]></failure>
    </testcase>
  </testsuite>
  <testsuite name="User" timestamp="2021-11-06T12:36:46" tests="3" file="C:\Users\artio\Desktop\6 Classes\8.2.classes\test\index.js" time="0.0010" failures="2">
    <testcase name="User should have method getTask" time="0.0000" classname="should have method getTask">
      <failure message="task name 1: expected 9 to equal &apos;task name 1&apos;" type="AssertionError"><![CDATA[AssertionError: task name 1: expected 9 to equal 'task name 1'
    at Context.<anonymous> (test\index.js:42:43)
    at processImmediate (internal/timers.js:439:21)]]></failure>
    </testcase>
    <testcase name="User should have method createTask" time="0.0000" classname="should have method createTask">
    </testcase>
    <testcase name="User should not implement method changeType" time="0.0000" classname="should not implement method changeType">
      <failure message="expected undefined to be a function" type="AssertionError"><![CDATA[AssertionError: expected undefined to be a function
    at Context.<anonymous> (test\index.js:55:41)
    at processImmediate (internal/timers.js:439:21)]]></failure>
    </testcase>
  </testsuite>
  <testsuite name="Admin" timestamp="2021-11-06T12:36:46" tests="7" file="C:\Users\artio\Desktop\6 Classes\8.2.classes\test\index.js" time="0.0020" failures="1">
    <testcase name="Admin should have method getArray" time="0.0000" classname="should have method getArray">
    </testcase>
    <testcase name="Admin should return instance of Guest as a first element by the method getArray" time="0.0000" classname="should return instance of Guest as a first element by the method getArray">
    </testcase>
    <testcase name="Admin should return instance of User as a third element by the method getArray" time="0.0000" classname="should return instance of User as a third element by the method getArray">
    </testcase>
    <testcase name="Admin should return array of roles by the method getArray" time="0.0010" classname="should return array of roles by the method getArray">
    </testcase>
    <testcase name="Admin should change type of role from Guest to User" time="0.0000" classname="should change type of role from Guest to User">
      <failure message="expected false to equal true" type="AssertionError"><![CDATA[AssertionError: expected false to equal true
    at Context.<anonymous> (test\index.js:84:56)
    at processImmediate (internal/timers.js:439:21)]]></failure>
    </testcase>
    <testcase name="Admin should change type of role from User to Guest" time="0.0000" classname="should change type of role from User to Guest">
    </testcase>
    <testcase name="Admin should move tasks from Guest to User, when change role" time="0.0000" classname="should move tasks from Guest to User, when change role">
    </testcase>
  </testsuite>
</testsuites>

Solution

  • Here is how i managed to do this task,it wasnt hard at all,but it was confusing:

    class Task {
        constructor(name) {
            this.name = name;
        }
    }
    class Guest {
        constructor(tasks) {
            this.tasks = tasks;
        }
        getTask(index) {
            return this.tasks[index];
        }
        createTask() {
            throw new Error("method 'createTask' is not defined");
        }
        changeType() {
            throw new Error("method 'changeType' is not defined");
        }
    }
    
    class User {
        constructor(tasks) {
            this.tasks = tasks;
        }
        getTask(index) {
            return this.tasks[index];
        }
        createTask(tasks) {
            return this.tasks.push(tasks);
        }
        changeType() {
            throw new Error("method 'changeType' is not defined");
        }
    }
    
    class Admin {
        constructor(userGuestArray) {
            this.userGuestArray = userGuestArray;
        }
        getArray() {
            return this.userGuestArray;
        }
    
        changeType(index) {
           let mainArray = this.userGuestArray;
           let arr = this.userGuestArray[index];
            if (mainArray[index] instanceof Guest) {
                mainArray[index] = new User(arr.tasks);
    
            } else if (mainArray[index] instanceof User) {
                mainArray[index] = new Guest(arr.tasks);
            }
            return mainArray;
        }
    }
    module.exports.Task = Task;
    module.exports.Guest = Guest;
    module.exports.User = User;
    module.exports.Admin = Admin;
    

    For the error part i should just throw one,thats why i got errors at test with the message that i should throw an error