incubator-couchdb-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Vlad GURDIGA <gurd...@gmail.com>
Subject Re: Testing shows and lists
Date Tue, 17 Nov 2009 02:50:37 GMT
Back on this one.

Insisting on the idea of separating the application code from the
pretty much standard kinda-template code of shows and lists, I came
out with a thing that feels cleaner.

In a list, let's say lists/tags.js, other than the template-code, I
only have an "<include code/lists/tags/html.js>" like:

function(head, req) {
  provides("html", function() {
    <include code/lists/tags/html.js>
    return result;
  });
}

The <include> thing is a kind of recursive "// !code" of CouchApp [1].
I'm using non-JavaScript, non-XML syntax deliberately to fail earlier
when something goes wrong and the file is not included. The "result"
variable is defined in the <include>d file "by convention" ;). I know
it's not really nice and readable but having "return" outside a
function (bear with me) is not allowed.

[1] "// !code" is non-recursive: CouchApp does not allow you to have
"// !code" in files included with "// !code", which is kinda pity
because you would have long-term benefits
(inherently-hierarchically-structured clean readable markup) with a
negligible short-term overhead (one-time pre-push in-lining).

Keeping it that short make it not-so-scary when you think about not
testing it exactly the same way as it runs inside CouchDB.

Now, in code/lists/tags/html.js I have all the application code that
is actually executable for real with "js -w -s" for both
syntax/compilation verification and tests:


<include code/lists/tags/mocks.js for tests>
<include lib/tools.js>

var row = getRow();
var tags = [];

while (row) {
  tags.push({
    name: row.key,
    count: row.value
  });

  row = getRow();
}

<include code/lists/tags/test.js for tests>

var result = "" +
<include code/lists/tags/html.e4x>


Here I have one more trick I could not achieve with "// !code":
conditional inclusion with <include some/file.ext for tests>.
It is readable and handy: the pre-push-test-related code and mocks are
not uploaded to CouchDB next to purely-application code.

The <include> thing is implemented by a little nice Perl script [2]
which gives me back the intuitive use of an include directive.

[2] http://github.com/gurdiga/cozy/blob/master/bin/process_includes.pl

It's not a lot of logic to test for now, which is a good thing, and
thanks to CouchDB for that, but it *could* break and we have to cover
our backs.

Now, having all the page markup in the "result" variable, we can of
course test everything we could possibly wish (E4X has convenient
means for that[3]), but considering browsers' quirks, it makes more
sense to do that inside browser.

[3] https://developer.mozilla.org/En/E4X/Processing_XML_with_E4X#Searching_and_filtering

This is what I have right now, probably not perfect, I expect it to
evolve further, so any improvement ideas of maybe even different
approaches would certainly be valuable for our community.


On Tue, Nov 3, 2009 at 2:05 PM, Vlad GURDIGA <gurdiga@gmail.com> wrote:
> Hello!
>
> How would someone test the application code inside shows and lists? Is
> there any recommended way or some best-practice?
>
> The actual page is probably more practical to test inside the browser
> with something like QUnit. But, before uploading the show to CouchDB
> I'd like to make sure it does not throw syntactical or other errors
> like undefined variable/function/whatever.
>
> If you get it to CouchDB in an "unstable" state it's pretty
> uncomfortable to find what's broken even from the logs when you have a
> page built up from more than a couple page components (with CouchApp
> macro-instructions like // !code and // !json).
>
> You can TDD the code you use all over the application by separating it
> into a library*. But how would you make sure that the page components
> and the other code that build up the page do actually glue up together
> nicely before uploading it?
>
> * http://github.com/gurdiga/cozy/tree/master/lib/
>
> Why before? Because it is an earlier feedback, and it is probably *a
> lot* faster to run it from command line with SpiderMonkey.
>
> Now,if you feed the show, which is an anonymous function to js, it
> only checks for syntactic correctness, because it does not actually
> run that function. You can try to kinda monkey-patch the function by
> adding "(" before and ")()" after the function body with a little
> shell script like this:
>
> #!/bin/sh
>
> echo "("
> cat $1
> echo ")();"
>
> and then use it like:
>
> $ ./mokey-patch.sh ./shows/page.js | js -w -s
>
> This way you would have that function ran and you'd find out that you
> need to mock up the "doc" and "req" variables if you have references
> to them in your code.
>
> When it comes to lists you get one more layer to penetrate: the code
> that you'll write is given as a closure to the "provides" function,
> and running the main list function with js does not actually run the
> code in the closure unless you will try to import somehow the original
> "provides" function from the CouchDB code, which seamed kinda scary to
> me and I abandoned this idea.
>
> The way which I ended up with was to kinda "export" the application
> code into a separate file named like "page.app.js" in which I have all
> my application code and which I inject back to the show file before
> "couchapp push" to CouchDB. Having it separate gives me the ability to
> make sure it runs before I get it on-line. Of course I have to fake
> all the data I get as arguments to the main function, but this turned
> out not to be that hard*.
>
> * http://github.com/gurdiga/cozy/blob/master/shows/book.app.js#L1
>
> The bad thing about my "approach" is that I get almost *twice as much
> code* uploaded to CouchDB as is actually ran by the show/list because
> the *.app.js is preprocessed by CouchApp and all the "// !code" macros
> are expanded.
>
> It is functional, it works, but it does not feel quite right. =(
>
> I'm kinda stuck here for now, so any good ideas are welcome. :)
>

Mime
View raw message