<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
    <title>Metadata-Helper Specs</title>

    <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/mocha/2.0.1/mocha.css">
    <link rel="stylesheet" href="style.css">

</head>
<body>

<h1><a href="index.html">Metadata-Helper</a></h1>

<div id="mocha"></div>

    <!-- testharness:js -->
    <script src="//cdnjs.cloudflare.com/ajax/libs/chai/1.10.0/chai.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/mocha/2.0.1/mocha.js"></script>

    <script>
        expect = chai.expect;
        mocha.setup('bdd');
    </script>

    <!-- Breeze -->
    <script src="https://rawgit.com/Breeze/breeze.js/master/build/breeze.debug.js"></script>
    <script src="https://rawgit.com/Breeze/breeze.js.labs/master/breeze.metadata-helper.js"></script>

    <!-- Tests -->
    <script src="tests.js"></script>

    <!-- CCJS Metadata in DocCode ... copy-and-pasted into ccjs.model.metadata.js in this plunker
    <script src="https://rawgit.com/Breeze/breeze.js.samples/master/net/DocCode/DocCode/tests/helpers/ccjs.model.metadata.js"></script>
    -->
    <script src="ccjs.model.metadata.js"></script>
    <script>
        mocha.run();
    </script>

</body>
</html>
/*
 *  Using Mocha and Chai BDD (expect) assertions: http://chaijs.com/api/bdd/
 */
describe('When client-defined CCJS metadata', function () {
    'use strict';

    var manager;

    beforeEach(function(){
        var dataService = new breeze.DataService({
            serviceName: '< no_server >',
            hasServerMetadata: false
        });
        
        var metadataStore = new breeze.MetadataStore();
        metadataStore.addDataService(dataService);
        docCode.testFns.ccjsFillMetadataStore(metadataStore);
        
        manager = new breeze.EntityManager({
          dataService: dataService,
          metadataStore: metadataStore
        });
       
    });
    
    
    it("can create a Session", function () {
        var session = manager.createEntity('Session', {
            title: "Metadata by Hand with Metadata-Helper",
            description: "Learn how to write Breeze metadata on the client with the Metadata-Helper"
        });
        expectAddedEntity(session);
    });

    it("can create a Session with a Speaker (Person)", function () {
        var person = manager.createEntity('Person', {
            firstName: 'Ward',lastName: 'Bell'
        });
        var session = manager.createEntity('Session', {
            title: "Metadata by Hand with Metadata-Helper",
            description: "Learn how to write Breeze metadata on the client with the Metadata-Helper",
            speaker: person
        });
        expectAddedEntity(session);
        expect(session.speaker.id).to.equal(person.id,
            "Session's speaker should be same as the person created");
    });
 
    it("can create a Speaker (Person) with multiple Sessions", function () {
        var person = manager.createEntity('Person', {
            firstName: 'Ward',lastName: 'Bell'
        });
        
        var session1 = manager.createEntity('Session', {
            title: "Metadata by Hand with Metadata-Helper",
            description: "Learn how to write Breeze metadata on the client with the Metadata-Helper",
            speaker: person
        });
        
        var session2 = manager.createEntity('Session', {
            title: "Breeze: our gift to the world",
            description: "Learn how Breeze solves world peace and cures diseases",
            speaker: person
        });
        
        // get those sessions by navigating from the person w/ `sessions` property
        var navSessions = person.speakerSessions;
        expect(navSessions.length).to.equal(2, "person should have two related sessions");
        expect(navSessions.indexOf(session1)).to.be.above(-1, 
          'should include session1');
        expect(navSessions.indexOf(session2)).to.be.above(-1, 
          'should include session2');  
    });   
    ////////////////
    function expectAddedEntity(entity, entityName) {
      var entityState = entity.entityAspect.entityState;
      entityName = entityName || "'"+entity.entityType.shortName + "'";
      
      expect(entityState.isAdded()).to.equal(true,
          "a created '" + entityName + 
          "' should have 'Added' state; its entityState is '" + 
          entityState + "'.");
    }
    
});

// Define this global for ccjs.model.metadata.js which expects it to be predefined.
docCode = window.docCode || {testFns: {}};

body {
  padding-left: 4px;
  font: 20px/1.5 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

a {
  color: #00B7FF;
}

#mocha {margin: 0;}
#Breeze Metadata By Hand with Metadata-Helper

The Breeze documentation page, 
["*Metadata By Hand*"](http://www.getbreezenow.com/documentation/metadata-by-hand),
describes why and how you can write Breeze metadata on the client
with help from the 
[Breeze Labs Metadata-Helper](https://github.com/Breeze/breeze.js.labs/blob/master/breeze.metadata-helper.js).

This plunker demonstrates through Mocha/Chai tests that you can use such metadata
in your application.

The metadata in this example are in the "*ccjs.model.metadata.js*" file.
They describe the Code Camper model in John Papa's
PluralSight Course 
["Building Data-Centric Single Page Applications with Breeze"](http://www.pluralsight.com/courses/table-of-contents/building-single-page-applications-breeze).
This model consists of Sessions, 
Persons (speakers), Rooms, Tracks, and TimeSlots.

These tests are based on tests in the "metadataOnClientTests.js" in the
[Breeze DocCode sample](http://www.getbreezenow.com/samples/doccode).
/**
 * CCJS Model Metadata by hand from John Papa's PluralSight Course
 * "Building Data-Centric Single Page Applications with Breeze"
 * http://www.pluralsight.com/courses/table-of-contents/building-single-page-applications-breeze
 *
 * Copied from 
 * https://rawgit.com/Breeze/breeze.js.samples/master/net/DocCode/DocCode/tests/helpers/ccjs.model.metadata.js
 */
// ReSharper disable InconsistentNaming
(function (testFns) {
    'use strict';

    testFns.ccjsFillMetadataStore = fillMetadataStore;

    /////// Create and configure a Metadata-Helper instance //////////

    // 'Identity' is the default key generation strategy for this app
    var keyGen = breeze.AutoGeneratedKeyType.Identity;
    // namespace of the corresponding classes on the server
    var namespace = 'CC.Model';

    // Breeze Labs: breeze.metadata.helper.js
    // https://github.com/IdeaBlade/Breeze/blob/master/Breeze.Client/Scripts/Labs/breeze.metadata-helper.js
    // The helper reduces data entry by applying common conventions
    // and converting common abbreviations (e.g., 'type' -> 'dataType')
    var helper = new breeze.config.MetadataHelper(namespace, keyGen);

    /////////////////
    function fillMetadataStore(store) {

        // DataTypes
        var DT = breeze.DataType;
        var BOOL = DT.Boolean;
        var DATE = DT.DateTime;
        var ID = DT.Int32;

        // type order is irrelevant
        addPerson();
        addSession();
        addRoom();
        addTimeSlot();
        addTrack();

        // addType - make it easy to add the type to the store using the helper
        function addType(type) {
            helper.addTypeToStore(store, type);
        }

        function addPerson() {
            addType({
                name: 'Person',
                dataProperties: {
                    id: { type: ID },
                    firstName: { max: 50, required: true },
                    lastName: { max: 50, required: true },
                    // could add validators here; let model.validation add them
                    email: { max: 400 },
                    blog: { max: 400 },
                    twitter: { max: 400 },
                    gender: { max: 1 },
                    imageSource: { max: 400 },

                    // could let Breeze add unmapped but we do so to lock in the Boolean data type
                    isPartial: { type: BOOL, required: true, isUnmapped: true },
                    isSpeaker: { type: BOOL, required: true, isUnmapped: true }
                },

                navigationProperties: {
                    speakerSessions: { type: 'Session', hasMany: true }
                }
            });
        }

        function addSession() {
            addType({
                name: 'Session',
                dataProperties: {
                    id: { type: ID },
                    title: { max: 50, required: true },
                    code: { max: 10 },
                    description: { max: 4000 },
                    level: { max: 30 },
                    tags: { max: 4000 },

                    roomId: { type: ID, required: true },
                    speakerId: { type: ID, required: true },
                    timeSlotId: { type: ID, required: true },
                    trackId: { type: ID, required: true },

                    isPartial: { type: BOOL, required: true, isUnmapped: true }
                },

                // Let model.validation add the requireReferenceEntity validators
                navigationProperties: {
                    room: 'Room',
                    speaker: 'Person',
                    timeSlot: 'TimeSlot',
                    track: 'Track'
                }

            });
        }

        function addRoom() {
            addType({
                name: 'Room',
                dataProperties: {
                    id: { type: ID },
                    name: { max: 50, required: true }
                }
            });
        }

        function addTimeSlot() {
            addType({
                name: 'TimeSlot',
                dataProperties: {
                    id: { type: ID },
                    start: { type: DATE, required: true },
                    isSessionSlot: { type: BOOL, required: true },
                    duration: { type: ID, required: true }
                }
            });
        }

        function addTrack() {
            addType({
                name: 'Track',
                dataProperties: {
                    id: { type: ID },
                    name: { max: 50, required: true }
                }
            });
        }
    }
})(docCode.testFns);