function testTree_JoinPredicates() {
  var treeBefore =
      'select(join_pred(Employee.jobId eq Job.id))\n' +
      '-select(join_pred(Employee.departmentId eq Department.id))\n' +
      '--cross_product\n' +
      '---cross_product\n' +
      '----table_access(Employee)\n' +
      '----table_access(Job)\n' +
      '---table_access(Department)\n';

  var treeAfter =
      'select(join_pred(Employee.departmentId eq Department.id))\n' +
      '-cross_product\n' +
      '--select(join_pred(Employee.jobId eq Job.id))\n' +
      '---cross_product\n' +
      '----table_access(Employee)\n' +
      '----table_access(Job)\n' +
      '--table_access(Department)\n';

  var constructTree = function() {
    var d = schema.getDepartment();
    var e = schema.getEmployee();
    var j = schema.getJob();

    var queryContext = new lf.query.SelectContext(hr.db.getSchema());
    queryContext.from = [e, j, d];
    var predicate1 = e.departmentId.eq(d.id);
    var predicate2 = e.jobId.eq(j.id);
    queryContext.where = lf.op.and(predicate1, predicate2);

    var crossProductNode1 = new lf.proc.CrossProductNode();
    crossProductNode1.addChild(
        new lf.proc.TableAccessNode(queryContext.from[0]));
    crossProductNode1.addChild(
        new lf.proc.TableAccessNode(queryContext.from[1]));
    var crossProductNode2 = new lf.proc.CrossProductNode();
    crossProductNode2.addChild(crossProductNode1);
    crossProductNode2.addChild(
        new lf.proc.TableAccessNode(queryContext.from[2]));

    var selectNode1 = new lf.proc.SelectNode(predicate1);
    selectNode1.addChild(crossProductNode2);
    var selectNode2 = new lf.proc.SelectNode(predicate2);
    selectNode2.addChild(selectNode1);


    return {queryContext: queryContext, root: selectNode2};
  };

  lf.testing.treeutil.assertTreeTransformation(
      constructTree(), treeBefore, treeAfter, pass);
}
Tests a tree that involves a 3 table join. It ensures that the JoinPredicate
nodes are pushed down until they become parents of the appropriate cross
product node.