Queue implementation in ES6
Does not work, can be mutated

You did not even test this object. Please take time to make sure the code you put up for review is at least working next time. :)

Bugs.

You don't tests if head is defined for the functions peek, and poll.

const q = new Queue();
q.peek(); // throws TypeError cannot read property val of null
q.poll(); // throws TypeError cannot read property next of null


Can only Get one object from the Queue per group of offer calls

q.offer("A");
q.offer("B");
q.poll(); // return "A"
q.peek(); // throws TypeError cannot read property val of null
q.poll(); // throws TypeError cannot read property next of null


// OR
q.offer("A");
q.offer("B");
q.poll(); // return "A"
q.offer("C");
q.poll(); // return "C"  What happened to "B"


Mutation

You have not encapsulated the object state and thus can be mutated in many ways to produce unexpected behaviours

const q = new Queue()
q.offer("foo");
q.head.tail = q.head;  
while(!q.isEmpty()) { console.log(q.poll().val) } // never stops

// and
q.head = undefined;
q.isEmpty(); // incorrectly returns false


Bloated

The property Queue.tail does nothing and is just noise. 

I am guessing you wanted to use it to make offer quicker without needing to step all the way down the links from head but that will require a doubly linked list. 

You could just use an array.