Simple scope
This example shows an advanced use case for testing a multi-URL application using various 'scopes'. It shows a bit about how scopes organize information and how to create a web framework test that contains more than one window, that saves and verifies all web page contents and logs.

To run:

scc -tw example/simpleScope

There are five domain objects in different scopes:

file: example/simpleScope/GlobalInfo.sc
@Sync
scope<global>
object GlobalInfo {
   String message = "All your base are belong to us";
}
file: example/simpleScope/GlobalPageInfo.sc
import sc.obj.AppGlobalScopeDefinition;

@Sync
scope<appGlobal>
object GlobalPageInfo {
   // Since this is created in the appGlobal scope, we'll use the API to access the current appGlobal context
   // and then use the 'id' as the initial value of the pageTitle.  It makes a nice way to see what scope we
   // are using for this page and also shows the apis.
   String pageTitle = AppGlobalScopeDefinition.getAppGlobalScope().getAppId();
}
file: example/simpleScope/PageUserInfo.sc
@Sync
scope<appSession>
object PageUserInfo {
   int numVisits;
   String userPageTitle = UserSession.userName + "'s " + GlobalPageInfo.pageTitle;
}
file: example/simpleScope/UserSession.sc
@Sync
scope<session>
object UserSession {
   String userName = "Fanny Bumpkin";
   int numPageViews;
}
file: example/simpleScope/WindowSession.sc
@Sync
scope<window>
object WindowSession {
   String windowName;
   int numWindowVisits;
}

A component that displays and updates properties above:

file: example/simpleScope/ScopeExample.schtml
<div id="ScopeExample">
   <i abstract="true" id="editField" style="text-indent: 40px; display: block"/>
   <input abstract="true" id="inputTag" type="text" style="width: 200px"/>

   Page title: <span><%= GlobalPageInfo.pageTitle %></span>
      <i extends="editField">Edit page title: <input extends="inputTag" value=":=: GlobalPageInfo.pageTitle"/></i>
   <p/>
   Global message: <span class="announcement"><%= GlobalInfo.message %></span>
      <i extends="editField">Edit message: <input extends="inputTag" value=":=: GlobalInfo.message"/></i>
   <p/>
   User name: <span><%= UserSession.userName %></span>
      <i extends="editField">Edit userName: <input type="text" value=":=: UserSession.userName"/></i>
   <p/>
   User page title: <span><%= PageUserInfo.userPageTitle %></span>
       <i extends="editField">Edit my name for this page: <input extends="inputTag" value=":=: PageUserInfo.userPageTitle"/></i>
   <p/>
   <span>Window visits <%= WindowSession.numWindowVisits %></span> (always '1')
   <br/>
   <span>Page visits <%= PageUserInfo.numVisits %></span> (counts times this user loads this page)
   <br/>
   <span>Session visits <%= UserSession.numPageViews %></span> (counts times this user loads any page)

   <%!
      public void onPageVisit() {
         WindowSession.numWindowVisits++;
         PageUserInfo.numVisits++;
         UserSession.numPageViews++;
      }
   %>
</div>

that's used in two different applications:

file: example/simpleScope/ScopePageFoo.schtml
<html pageVisitCount="=: body.appFrame.onPageVisit()">
<body>
   Application Foo
   <div id="appFrame" extends="ScopeExample"/>
</body>
</html>
file: example/simpleScope/ScopePageBar.schtml
<html pageVisitCount="=: body.appFrame.onPageVisit()">
<body>
   Application Bar
   <div id="appFrame" extends="ScopeExample"/>
</body>
</html>

A test wrapper that loads two windows for each application:

file: example/simpleScope/ScopeTest.schtml
<html id="ScopeTest" refreshOnLoad="false">
   <body>
      <iframe abstract="true" id="pageFrame" style="width:45%;height:280px"></iframe>
      <!-- Adding the scopeContextName param in the iframe URLs so we can 'attach' to each scope from the test script (see testScript.scr) 
           Adding windowId for consistency in the captured test page output.  Otherwise, the windowIds are assigned based on when requests are
           received in a session.  Starting at 100 in case the session is used for other tests. -->
      <iframe extends="pageFrame" src='ScopePageFoo.html?scopeContextName=foo1&windowId=100'></iframe>
      <iframe extends="pageFrame" src='ScopePageFoo.html?scopeContextName=foo2&windowId=101'></iframe>
      <iframe extends="pageFrame" src='ScopePageBar.html?scopeContextName=bar1&windowId=102'></iframe>
      <iframe extends="pageFrame" src='ScopePageBar.html?scopeContextName=bar2&windowId=103'></iframe>
   </body>
</html>

A test script to drive the whole thing. GlobalInfo and UserSession are shared by all four frames. GlobalPageInfo and PageUserInfo are different for ScopePageFoo and ScopePageBar but shared by the two frames for each application.

file: example/simpleScope/testScript.scr
cmd.includeSuper();

pageLoader.loadPageAndWait("ScopeTest", "scopeTestPage", null);

cmd.pauseTime = 250;

// GlobalInfo and UserSession classes are not defined in the JS runtime
// If we target the 'js' runtime we will get an error in trying to run this command
// By setting the targetRuntime, we the following commands only run on the server
cmd.targetRuntime = "java_Server";

GlobalInfo {
   message = message.replace("are", "were");
}

UserSession {
   userName = "Fanny Bumpkiss";
}

// In ScopeTest, we add ?scopeContextName=foo1 to the URL for one of the iframes.  This command waits for the server to receive a sync request
// from that browser.  When it returns, the following commands have cmd.syncContextState set to that page's context.  So PageInfo will map to
// the PageInfo for that page, WindowSession the window for that Page, and PageUserInfo the per-session user info for that user.
cmd.waitForReady("foo1", pageLoader.waitForPageTime);

GlobalPageInfo {
   pageTitle = "A page named foo";
}

WindowSession {
   windowName = "The original foo window";
}

PageUserInfo {
   userPageTitle = "Fanny's foo";
}

ScopePageFoo {
   pageLoader.savePage("ScopePageFoo", serverTag ? pageLoader.getClientBodyHTML("foo1") : output_c().toString());
   pageLoader.savePage("ScopePageFoo", output().toString());
}

cmd.waitForReady("bar2", pageLoader.waitForPageTime);
GlobalPageInfo {
   pageTitle = "A page named bar";
}

WindowSession {
   windowName = "The second bar window";
}

PageUserInfo {
   userPageTitle = "Fanny's bar";
}

ScopePageBar {
   pageLoader.savePage("ScopePageBar", serverTag ? pageLoader.getClientBodyHTML("bar2") : output_c().toString());
   pageLoader.savePage("ScopePageBar", output().toString());
}
The scopeContextName in the URL identifies each window, and allows the script to set properties specific to a specific one.

It waits and sets some properties in the foo1 instance of ScopePageFoo and then the same for the bar2 instance of ScopePageBar.