@@ -0,0 +1,1699 @@
+package org.realityforge.arez.api2;%0A%0Aimport org.realityforge.guiceyloops.shared.ValueUtil;%0Aimport org.testng.annotations.Test;%0Aimport static org.testng.Assert.*;%0A%0Apublic class TransactionTest%0A  extends AbstractArezTest%0A%7B%0A  @Test%0A  public void construction()%0A  %7B%0A    final ArezContext context = new ArezContext();%0A    final String name1 = ValueUtil.randomString();%0A    final int nextNodeId = context.currentNextNodeId();%0A%0A    final Transaction transaction = new Transaction( context, null, name1, null );%0A%0A    assertEquals( transaction.getName(), name1 );%0A    assertEquals( transaction.getContext(), context );%0A    assertEquals( transaction.getId(), nextNodeId );%0A    assertEquals( transaction.getPrevious(), null );%0A    assertEquals( transaction.getTracker(), null );%0A    assertEquals( transaction.getObservables(), null );%0A    assertEquals( transaction.getPendingPassivations(), null );%0A%0A    assertEquals( context.currentNextNodeId(), nextNodeId + 1 );%0A  %7D%0A%0A  @Test%0A  public void trackingCycleWithNoTracker()%0A  %7B%0A    final ArezContext context = new ArezContext();%0A    final Transaction transaction = new Transaction( context, null, ValueUtil.randomString(), null );%0A%0A    final TestObservable observable = new TestObservable( context, ValueUtil.randomString() );%0A%0A    assertEquals( observable.getObservers().size(), 0 );%0A    assertEquals( transaction.getObservables(), null );%0A%0A    //Transaction should perform no action during tracking if there is no associated tracker%0A    transaction.beginTracking();%0A    transaction.observe( observable );%0A    transaction.completeTracking();%0A%0A    assertEquals( observable.getObservers().size(), 0 );%0A    assertEquals( transaction.getObservables(), null );%0A  %7D%0A%7D%0A

Add some basic unit tests for transaction